
简介基于Java的砂石矿山管理系统设计与实现毕业设计资料面向计算机专业毕业生及SSM框架学习者。系统围绕矿山砂石销售业务包含登录校验、销售登记自动计算单价乘以载重总价、员工信息维护、加班登记与查询、销售账单按公司、车牌、日期或支付状态统计、其他账目收支记录等完整功能模块并附毕业论文文档可用于课程设计或论文撰写参考。资源包共885个文件大小9.79MB以Java源码、JSP页面、CSS与JS前端资源、SQL脚本及论文文档为主其中87个Java文件支撑业务逻辑59个JSP与25个HTML构成页面118个CSS和232个JS实现界面样式与交互另含图片素材和数据库初始化脚本目录结构适合按模块对照学习。目前已有103人浏览学习。通过完整源码、数据库脚本和论文内容可了解需求分析、数据库设计、SSM整合及前后端协作的完整思路便于按模块理解部署和二次开发。1. 砂石矿山管理系统一个能落地也能毕业的 Java SSM 选题提到 Java 毕业设计十个里有七个是图书管理系统、学生选课。这套基于 Java SSM 的砂石矿山管理系统思路更往传统行业靠砂石场的销售还在用 Excel 记账公司、车牌、砂石种类、单价、载重全靠手敲月底对账要翻半天记录。功能都是实际业务登录不可注册、销售登记单价×载重自动算总价、日期自动获取、人员与加班登记、多条件查询汇总、其他账目倒序查询。技术栈 SSM Bootstrap配套毕业论文适合毕设交差也适合真想给砂石场换套记账方式的人。这篇按我拆这个项目的顺序走先看工程结构与登录设计再讲销售登记和查询统计的 SQL 与计算逻辑最后把最容易翻车的几个点单独列出。新手照步骤能跑通熟手直接看避坑章。2. SSM 骨架与登录模块从 Eclipse 工程结构到预置账号2.1 .classpath 文件里的项目出身下载解压后最先看到的是一批 Eclipse 工程文件.classpath、org.eclipse.wst.common.component、org.eclipse.wst.jsdt.ui.superType.container。别急着删它们明确告诉你一个信息项目是在 Eclipse 系 IDE 里手工建的不是 Maven 工程。.classpath 里记录的是源码目录 src、输出目录 build/classes、JDK 版本以及 WebRoot/WEB-INF/lib 下的一堆 jar 依赖。读 .classpath 的实际作用有两个。第一确认 JDK 版本——我见过不少人本机装的是 JDK 17项目还是 1.8 语法一跑就报 UnsupportedClassVersionError。第二确认依赖管理方式是 lib 目录导入时直接用 Eclipse 的 Import Existing Projects 就能进不用等 Maven 下载。静态资源 style.css、bootstrap.min.css 都放在 WebRoot 下部署到 Tomcat 后直接可访问不走打包流程。一个典型的 .classpath 片段长这样classpath classpathentry kindsrc pathsrc/ classpathentry kindcon pathorg.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8/ classpathentry kindoutput pathbuild/classes/ /classpathkindsrc 是 Java 源码根目录kindcon 表示容器依赖这里能看到 JavaSE-1.8 字样output 是编译输出目录。导入后如果项目报红叉回头对照这三项源码目录对不对、JDK 对不对、lib 有没有被引用。2.2 SSM 四件套jdbc.properties 与两个 XML 的关键行SSM 在老 Eclipse 项目里的配置是固定套路jdbc.properties 放数据库连接spring-mvc.xml 管 Controller 扫描和视图解析applicationContext.xml 管 Spring 容器与 MyBatis 集成mybatis-config.xml 管 mapper 注册。先看 jdbc.properties这是启动第一关jdbc.drivercom.mysql.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/sand_mine?useUnicodetruecharacterEncodingutf-8 jdbc.usernameroot jdbc.password123456本机是 MySQL 8.x 的话driver 换成 com.mysql.cj.jdbc.Driverurl 末尾加 serverTimezoneAsia/Shanghai。数据库名 sand_mine 要和初始化脚本里的建库名一致编码必须带 utf-8否则中文全变问号。改完这三行第一关才算过。spring-mvc.xml 里两个关键配置context:component-scan base-packagecom.sand.controller/ bean classorg.springframework.web.servlet.view.InternalResourceViewResolver property nameprefix value/WEB-INF/jsp// property namesuffix value.jsp/ /beanbase-package 必须覆盖 Controller 所在包扫不到就是 404。prefix 和 suffix 决定了 Controller 里 return login 会去找 /WEB-INF/jsp/login.jsp——JSP 不在这里或目录名不叫 jsp页面就白屏。很多登录页打不开的翻车就出在这一行。mybatis-config.xml 里容易出问题的是 mapper 注册。手工项目常见做法是逐个列mappers mapper resourcecom/sand/mapper/UserMapper.xml/ mapper resourcecom/sand/mapper/SaleMapper.xml/ mapper resourcecom/sand/mapper/EmployeeMapper.xml/ /mappers每新增一个 Mapper XML 都要来这里注册漏了会报 Invalid bound statement (not found)。这个报错我答疑时见了几十次全是注册遗漏或 namespace 写错。提示改完任何 XML 配置都要重启 TomcatSpring 容器只在启动时加载一次配置热部署不一定生效。2.3 登录不可注册预置账号与密码比对登录提示账号不存在或者密码错误两个场景共用一句话不暴露账号是否存在这是安全上的好习惯。系统没有注册入口账号来自初始化 SQL 预置。配套毕业论文里 ER 图和用例图对应的就是下面这几张表登录模块对应的就是 t_user 这一张CREATE TABLE t_user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL, password VARCHAR(64) NOT NULL ); INSERT INTO t_user (username, password) VALUES (admin, MD5(123456));密码存 MD5登录时把输入转 MD5 再比对不落明文。答辩时老师追问密码安全能答出这一句比多说一个功能都加分。Service 层逻辑public User login(String username, String password) { String md5pwd DigestUtils.md5Hex(password); User user userMapper.findByUsername(username); if (user ! null user.getPassword().equals(md5pwd)) { return user; } return null; }Controller 拿到 null 统一提示账号不存在或者密码错误。session 里放 user 对象再用一个 Filter 拦截未登录请求。很多课设只做 JSP 页面跳转判断自己补一个 Filter 工作量不大答辩能讲的东西多一样。到这里骨架和入口就算摸清了下一步是核心业务——销售登记。3. 销售登记与总价计算下拉数据源、自动日期与前后端分工3.1 下拉数据源固定字典与动态列表销售登记页有公司、车牌、砂石种类、单价、载重几个核心输入。砂石种类固定四种粗砂、细沙、粉砂、块石这种变化极小的数据写死在 JSP 的 select 里也行但放字典表更规范。公司列表、车牌列表是动态数据进页面时 Controller 从对应表查出来塞进 ModelAndViewRequestMapping(/sale/add) public ModelAndView addPage() { ModelAndView mv new ModelAndView(sale/add); mv.addObject(companyList, companyMapper.findAll()); mv.addObject(plateList, plateMapper.findAll()); return mv; }JSP 用 JSTL 渲染select namecompanyId classform-control c:forEach items${companyList} varcompany option value${company.id}${company.name}/option /c:forEach /select这里有个新手必踩的点提交的是 companyId不是公司名称。很多人直接把名称入库后续按公司查询只能模糊匹配没法做精确关联。数据库设计时公司表、车牌表各一张销售表只存外键 id页面显示 name这是外键关联的标准分工。车牌表如果和公司有归属关系还可以加一个 company_id 字段做选了公司自动过滤车牌的联动这是这个模块可以自己加的一个小升级。3.2 总价 单价 × 载重前端实时算后端必须重算前端要给操作员实时反馈让单价和载重的 change 事件都绑到同一个计算函数上function calcTotal() { var price parseFloat($(#price).val()) || 0; var weight parseFloat($(#weight).val()) || 0; $(#totalPrice).val((price * weight).toFixed(2)); } $(#price).change(calcTotal); $(#weight).change(calcTotal);parseFloat 解析失败会得到 NaN|| 0 做兜底。toFixed(2) 保留两位小数。但前端计算的职责只是用户体验保存时后端必须重算因为请求可以被绕过前端算出来的数字不可信BigDecimal totalPrice price.multiply(weight); sale.setTotalPrice(totalPrice);单价、载重、总价都用 BigDecimal别用 double。double 做乘法会出现 0.10.20.30000000000000004 这种玄学误差金额字段用 double 是给自己埋雷。数据库字段类型也对应 DECIMAL(10,2)Java 算完再写进表两头口径一致。3.3 日期自动获取前端默认值加后端兜底需求里的日期自动获取指的是打开登记页时默认填当天操作员大多数时候不用改。JS 实现function today() { var d new Date(); var month (d.getMonth() 1) 10 ? 0 (d.getMonth() 1) : (d.getMonth() 1); var day d.getDate() 10 ? 0 d.getDate() : d.getDate(); return d.getFullYear() - month - day; } $(#saleDate).val(today());getMonth() 从 0 开始所以要 1月日补零是因为数据库 DATE 类型更习惯 yyyy-MM-dd 字符串。后端保存时再兜底一次提交为空就用数据库 CURRENT_DATE。如果字段是 DATETIME 而前端只传日期字符串时间部分会变成 00:00:00对纯日期统计影响不大但要留意下一节说的日期边界问题。3.4 人员与加班登记两张表的字段设计人员登记是标准增删改查姓名、年龄、本人电话号码、紧急联系人号码。年龄用 INT手机号用 VARCHAR(20)——电话号码开头可能有 0将来存座机分机号也不怕用 INT 会吃掉前导零。加班表存 employee_id 和 overtime_hours员工表主键是加班表的外键。加班时长用 DECIMAL(4,1)能存 3.5 小时别用 INT。现实中加班三个半小时很常见用 INT 要么把单位改成分钟要么只能四舍五入。删除员工时要注意如果该员工已有加班记录直接删会报外键约束错误要么先删加班记录要么加一个逻辑删除字段 is_deleted这个可以在论文里写成数据完整性设计的一节。4. 查询统计多条件组合 SQL、倒序账目与加班聚合4.1 销售查询四个条件任意组合需求里最有含金量的是查询查询柏松房产在 1 月 1 日到 1 月 10 日还未支付的所有订单及总账、查询贵A5236 该车的 1 月总账单。这是典型的多条件组合查询公司、车牌、日期区间、支付状态每个条件可能为空也可能同时生效。MyBatis 的whereif就是为这个场景设计的select idquerySales resultTypecom.sand.entity.SaleVO SELECT s.*, c.name AS companyName, p.plate_no AS plateNo FROM t_sale s LEFT JOIN t_company c ON s.company_id c.id LEFT JOIN t_plate p ON s.plate_id p.id where if testcompanyId ! null and companyId ! AND s.company_id #{companyId} /if if testplateId ! null and plateId ! AND s.plate_id #{plateId} /if if teststartDate ! null and startDate ! AND s.sale_date gt; #{startDate} /if if testendDate ! null and endDate ! AND s.sale_date lt; #{endDate} /if if testpayStatus ! null and payStatus ! AND s.pay_status #{payStatus} /if /where ORDER BY s.sale_date DESC /select要点有三个。where会自动去掉第一个条件多余的 AND所以每个 if 里放心写 AND。XML 里大于小于号必须转义成gt;和lt;这是 XML 语法层面的问题不转义文件直接解析失败。日期比较传 yyyy-MM-dd 字符串即可前提是字段是 DATE 类型。查询条件从页面穿过来时Controller 里 new 一个 query 对象让 SpringMVC 自动绑定 request 参数Mapper 方法直接传对象就行。销售记录积累到几百上千条后建议加分页老项目常用 PageHelper一个 PageHelper.startPage(pageNum, pageSize) 接在查询前就能生效手工 SQL 分页就是 LIMIT。毕业设计答辩提一句分页是个不错的加分点。4.2 汇总账单SUM 查询与条件片段复用需求要总账明细列表之外还要合计金额。两个做法Java 遍历累加或者 SQL 里 SUM。数据量小都能用但我推荐 SQL 层面做——明细一旦分页Java 累加只加当前页账就错了。sql idsaleWhere where ... 和 querySales 里完全相同的条件 ... /where /sql select idsumSales resultTypejava.math.BigDecimal SELECT COALESCE(SUM(total_price), 0) FROM t_sale s include refidsaleWhere/ /selectsql把条件抽出来两个查询 include 同一片段保证条件永远一致。COALESCE 处理空结果没记录时返回 0 而不是 null页面显示 0.00 比 null 好看。这是 MyBatissql标签最典型的用法答辩讲这个点能体现对框架的理解不止 CRUD。注意前端页面上显示的汇总数字只供查看写进报表或打印出来的金额必须走后端 SUM 接口两边口径在验收时对一遍。4.3 其他账目倒序与加班时长聚合其他账目开支查询按照倒序罗列——SQL 就是 ORDER BY create_time DESC, id DESC。只按 create_time 排如果多个账目在同一秒入库顺序不稳定加 id DESC 做次级排序保证记录顺序固定这个细节在答辩讲数据一致性时可以提。员工加班时长查询是某个员工某月某日到某月某日的总加班时长select idsumOvertime resultTypejava.math.BigDecimal SELECT COALESCE(SUM(overtime_hours), 0) FROM t_overtime WHERE employee_id #{employeeId} AND overtime_date gt; #{startDate} AND overtime_date lt; #{endDate} /selectstartDate 传当月第一天endDate 传当月最后一天。这里有个隐藏边界如果 overtime_date 是 DATE 类型endDate 传 2025-01-31能包含当天但如果是 DATETIME 类型2025-01-31 会被转成 2025-01-31 00:00:00当晚的数据就丢了。查不到数据先别怀疑 SQL先看表结构这是我反复踩过的坑下一章展开讲。5. 避坑指南数据库连接、日期边界与中文乱码的五个现场这五个问题是我在同类 SSM 项目里见得最多的前四个几乎每个来问的人都会中一个。每条按现象、原因、解决的顺序写方便对照排查。5.1 启动报错Communications link failure现象Tomcat 启动时控制台抛 Communications link failure或者 Access denied for user rootlocalhost登录页一直打不开。原因三选一。MySQL 服务没启动jdbc.properties 里用户名或密码写错MySQL 8 没换 cj 驱动导致协议不兼容。解决先命令行敲 mysql -uroot -p 验证数据库能连再核对 jdbc.properties 三行配置MySQL 8 把 driver 换成 com.mysql.cj.jdbc.Driverurl 末尾加 serverTimezoneAsia/Shanghai。改完重启 Tomcat不要只刷新页面配置是启动时读取的。5.2 下拉列表空白现象销售登记页公司下拉框是空的F12 看请求返回 200但 select 里没有 option。原因Controller 没查列表塞进 ModelJSP 的 c:forEach 写错或者 JSTL 标签库没引入。前两种最常见。解决Controller 里 addObject 两个列表JSP 顶部写 % taglib prefixc urihttp://java.sun.com/jsp/jstl/core %确认 lib 下有 jstl 和 standard 两个 jar。JSP 编译错误经常被 Tomcat 吞掉只显示 500要去 catalina 日志里看具体原因日志里会有 Attribute companyList invalid 之类的明确提示。5.3 日期范围查询漏掉最后一天现象查 1 月 1 日到 1 月 10 日1 月 10 日当天登记的数据查不出来。原因日期字段是 DATETIME 类型2025-01-10 被 MySQL 转成 2025-01-10 00:00:00当天 00:00:00 之后的记录全部被过滤掉。解决两个方案。一是查询条件里把 endDate 加一天用 下一天而不是 endDate二是业务日期字段直接设计成 DATE 类型。我在不止一个项目里被 DATETIME 边界坑过现在一律先看表结构再写查询条件这已经成了习惯。5.4 中文乱码姓名变问号现象登记的中文姓名、公司名保存后变问号或者页面显示乱码。原因三层都可能——JSP 页面编码不是 UTF-8Tomcat 请求解码不是 UTF-8数据库连接 url 没带 characterEncoding或者表本身是 latin1。解决JSP 顶部 pageEncodingUTF-8web.xml 里配 CharacterEncodingFilter 强制 request 编码jdbc url 带 useUnicodetruecharacterEncodingutf-8建表统一 utf8mb4。改完清掉乱码数据重新测试别在脏数据基础上继续改越改越乱。5.5 页面 404 但映射存在现象访问 /sale/add 直接 404Controller 的 RequestMapping 检查过没问题Tomcat 也正常启动。原因spring-mvc.xml 组件扫描包路径不对Controller 没被 SpringMVC 容器扫描到或者 web.xml 里 DispatcherServlet 的 url-pattern 配成了 *.jspJSP 请求永远不进 SpringMVC。解决核对context:component-scan的 base-package 是否包含 Controller 所在包DispatcherServlet 的 url-pattern 一般配 /JSP 由 InternalResourceViewResolver 处理。改完重启看启动日志是否输出了 RequestMappingHandlerMapping 的映射记录有输出就说明 Controller 注册成功了。6. 部署走查与对账验收跑通全流程的最后一公里6.1 导入与启动步骤Eclipse 里 Import Existing Projects 选整个目录确认编译级别和自己本机 JDK 一致这类 SSM 老项目基本是 1.8Build Path 不报红。执行初始化 SQL 建库改 jdbc.properties 三行右键项目 Run As - Run on Server 选 Tomcat。访问路径是 http://localhost:8080/项目名/项目名对应 web.xml 里的 context path登录账号就是初始化脚本里预置的 admin/123456。登录后第一件事不是录数据而是把每个菜单点一遍确认页面能开、下拉有数据。然后再按下面的清单走功能验收。6.2 功能验收清单模块操作预期结果登录输入 admin/123456进入首页登录输入错误密码提示账号不存在或密码错误销售登记选公司、车牌、粗砂填 60 元/吨、30 吨总价自动显示 1800.00日期为当天销售登记载重留空提交后端拦截或提示必填销售查询柏松房产 1月1日到1月10日 未支付只出该范围内未支付订单汇总金额正确加班查询选员工 起止日期返回区间内总加班时长其他账目新增油款 75000 未付倒序列表显示在最上面汇总对账有个习惯我一直在用页面查完打开数据库用同一组条件再跑一遍 SELECT SUM两边数字一致才敢算出账正确。对不上就查分页有没有截断汇总或者条件参数是不是被前端漏传了。从那以后我每次做完带统计功能的页面都会强制走一遍页面对账这个动作拿初始化数据把每个汇总口径验一遍再交出去。希望帮到你。本文还有配套的精品资源点击获取