news 2026/11/2 6:01:17

SSM+JSP小工程预算系统毕设实战:从环境搭建到答辩部署

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SSM+JSP小工程预算系统毕设实战:从环境搭建到答辩部署

简介:这份资源是面向高校计算机相关专业学生的Java毕业设计完整项目包,主题为基于SSM+JSP的小工程预算管理系统,适合正在准备毕业设计或课程设计、需要一套可运行参考方案的学习者。项目采用B/S架构,以Java为开发语言,后端整合Spring、SpringMVC与MyBatis框架,前端使用JSP页面,数据库选用MySQL,覆盖用户管理、装修材料管理、订单信息管理、工程信息管理、工程订单管理及材料分类管理等核心业务模块,功能结构贴近实际小型工程预算场景。压缩包共收录1272个文件,包含120个Java源文件、109个JSP页面、364个JavaScript脚本、146个CSS样式表以及大量png、gif、jpg图片资源和sql脚本、xml配置等,整体约32.88MB,目录层次分明,便于按模块阅读与二次开发。资源同时附带演示录像与说明文档,可帮助读者快速理解系统运行流程、数据库表结构与前后端交互逻辑,为撰写论文、搭建环境及答辩准备提供完整参考。目前已有100人学习下载。

1. 小工程预算系统为什么还在用 SSM+JSP:一个被低估的毕设选题

如果你正在翻毕业设计选题,看到「基于SSM+JSP的小工程预算Java毕业设计」这个标题,第一反应可能是:这技术栈是不是太老了?Spring Boot 都出到 3.x 了,谁还用 JSP?但我要说一个反直觉的结论——对于计算机毕业设计这个特定场景,SSM+JSP 反而是最不容易翻车的组合。原因很现实:JSP 是服务端渲染,页面跳转逻辑直观,调试时浏览器地址栏直接能看到请求路径,出了问题一眼就能定位是 Controller 没映射上还是 SQL 写错了。而小工程预算这个业务场景,天然适合 CRUD 密集型系统——工程项目录入、预算科目管理、费用明细增删改查、汇总报表导出,这些需求用 SSM 的三层架构(Controller-Service-DAO)拆下来,结构清晰,代码量可控,答辩时也容易讲清楚每一层在干什么。这篇文章面向的是正在做毕设的本科生,以及需要快速交付一个可运行 Java Web 项目的开发者。我会从环境搭建讲到核心模块实现,再到打包部署和答辩演示的注意事项,把整个落地路径拆开揉碎讲一遍。

2. 环境搭建与 SSM 整合:从零到跑通第一个 JSP 页面

2.1 版本选型:为什么我坚持用 JDK 8 + Tomcat 8.5 + MySQL 5.7

毕业设计最怕的不是功能少,而是环境跑不起来。我见过太多人卡在「Tomcat 启动报 404」或者「MySQL 连接超时」上,最后功能没写几个,时间全花在配环境了。所以版本选型的第一原则是:选成熟稳定的老版本,不追新。

组件推荐版本理由
JDK1.8SSM 生态最兼容,Spring 4.x/5.x 都支持
Tomcat8.5.x对 JSP 支持最稳定,9.x 有部分 API 变动
MySQL5.7驱动包成熟,mysql-connector-java5.1.x 直接可用
Maven3.6+依赖管理,避免手动导 jar 包
IDEA2021.x 及以上对 Maven Web 项目支持好,社区版够用

注意:如果你的学校要求用 MySQL 8.x,需要把驱动换成mysql-connector-java8.0.x,并且 JDBC URL 要加时区参数serverTimezone=Asia/Shanghai,否则会报时区错误。

2.2 Maven 项目骨架与 SSM 依赖配置

在 IDEA 里新建 Maven Web 项目后,pom.xml是整个项目的根基。下面是我常用的依赖配置,直接抄:

<dependencies> <!-- Spring 核心 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.3.20</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.3.20</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.3.20</version> </dependency> <!-- MyBatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.9</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.7</version> </dependency> <!-- 数据库驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.49</version> </dependency> <!-- 连接池 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.8</version> </dependency> <!-- JSP 相关 --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> </dependencies>

这段配置里,javax.servlet-api的scope必须是provided,因为 Tomcat 自带 servlet 容器,打包时不需要重复包含。JSTL 是 JSP 标准标签库,后面页面里用<c:forEach>遍历数据就靠它。

2.3 web.xml 与 Spring MVC 核心配置

web.xml是传统 Java Web 项目的入口,SSM 整合的关键配置都在这里。核心是注册DispatcherServlet和ContextLoaderListener:

<!-- Spring 上下文监听器,加载 applicationContext.xml --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- Spring MVC 前端控制器 --> <servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-mvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!-- 字符编码过滤器,解决中文乱码 --> <filter> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>

这里有个容易翻车的点:url-pattern写/而不是/*。写/*会拦截所有请求包括 JSP 文件本身,导致页面返回源码而不是渲染结果。写/只拦截 Controller 映射,JSP 由 Tomcat 的 JspServlet 处理。

2.4 用一个小页面验证 SSM 是否跑通

配置写完后,别急着写业务代码,先写一个最简单的 Controller 和 JSP 页面验证环境:

@Controller public class TestController { @RequestMapping("/test") public String test(Model model) { model.addAttribute("msg", "SSM 环境搭建成功"); return "test"; // 对应 /WEB-INF/jsp/test.jsp } }
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head><title>测试页</title></head> <body> <h2>${msg}</h2> </body> </html>

启动 Tomcat,浏览器访问http://localhost:8080/项目名/test,如果页面显示「SSM 环境搭建成功」,说明 Spring MVC 的视图解析器配置正确。如果 404,检查spring-mvc.xml里视图解析器的prefix和suffix是否配成了/WEB-INF/jsp/和.jsp。如果 500,看控制台堆栈,大概率是 jar 包冲突或者 MyBatis 映射文件路径没配对上。

3. 小工程预算核心业务模块:从数据库设计到 JSP 页面渲染

3.1 数据库表设计:五张表撑起整个预算系统

小工程预算系统的数据模型不复杂,核心就是「项目-科目-明细」三层结构。我一般设计五张表:

-- 用户表 CREATE TABLE sys_user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(100) NOT NULL, real_name VARCHAR(50), role VARCHAR(20) DEFAULT 'user' ); -- 工程项目表 CREATE TABLE project ( id INT PRIMARY KEY AUTO_INCREMENT, project_name VARCHAR(100) NOT NULL, project_code VARCHAR(50) UNIQUE, manager VARCHAR(50), start_date DATE, status TINYINT DEFAULT 1 -- 1进行中 2已完工 ); -- 预算科目表 CREATE TABLE budget_subject ( id INT PRIMARY KEY AUTO_INCREMENT, subject_name VARCHAR(50) NOT NULL, subject_code VARCHAR(30), parent_id INT DEFAULT 0 ); -- 预算明细表 CREATE TABLE budget_detail ( id INT PRIMARY KEY AUTO_INCREMENT, project_id INT NOT NULL, subject_id INT NOT NULL, amount DECIMAL(12,2) NOT NULL, remark VARCHAR(200), create_time DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (project_id) REFERENCES project(id), FOREIGN KEY (subject_id) REFERENCES budget_subject(id) );

金额字段用DECIMAL(12,2)而不是FLOAT,这是血泪经验——浮点数做金额汇总会出现0.1+0.2=0.30000000000000004的问题,答辩时被老师问到这个就尴尬了。

3.2 MyBatis 映射文件与 DAO 层实现

以预算明细的查询为例,Mapper XML 里写自定义 SQL 做多表关联:

<select id="selectDetailByProject" resultMap="detailMap"> SELECT d.id, d.amount, d.remark, d.create_time, s.subject_name, p.project_name FROM budget_detail d LEFT JOIN budget_subject s ON d.subject_id = s.id LEFT JOIN project p ON d.project_id = p.id WHERE d.project_id = #{projectId} ORDER BY d.create_time DESC </select> <resultMap id="detailMap" type="com.entity.BudgetDetail"> <id property="id" column="id"/> <result property="amount" column="amount"/> <result property="subjectName" column="subject_name"/> <result property="projectName" column="project_name"/> </resultMap>

resultMap的作用是解决数据库列名和 Java 属性名不一致的问题。比如数据库是subject_name,Java 实体里是subjectName,没有 resultMap 就映射不上,查出来是 null。

Service 层做事务控制,在applicationContext.xml里配好事务管理器后,用注解即可:

@Service @Transactional public class BudgetServiceImpl implements BudgetService { @Autowired private BudgetDetailMapper detailMapper; @Override public List<BudgetDetail> getDetailsByProject(Integer projectId) { return detailMapper.selectDetailByProject(projectId); } @Override public BigDecimal getTotalAmount(Integer projectId) { List<BudgetDetail> list = detailMapper.selectDetailByProject(projectId); return list.stream() .map(BudgetDetail::getAmount) .reduce(BigDecimal.ZERO, BigDecimal::add); } }

汇总金额用BigDecimal的reduce做累加,不要用double循环相加,精度问题在预算系统里是致命的。

3.3 JSP 页面用 JSTL 渲染预算明细列表

JSP 页面里用 JSTL 标签遍历后端传来的 List,这是传统 JSP 项目最核心的展示方式:

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> <table border="1"> <tr> <th>科目名称</th><th>金额</th><th>备注</th><th>录入时间</th> </tr> <c:forEach items="${detailList}" var="d"> <tr> <td>${d.subjectName}</td> <td><fmt:formatNumber value="${d.amount}" pattern="#,##0.00"/></td> <td>${d.remark}</td> <td><fmt:formatDate value="${d.createTime}" pattern="yyyy-MM-dd HH:mm"/></td> </tr> </c:forEach> </table>

<fmt:formatNumber>做千分位格式化,<fmt:formatDate>做日期格式化,这两个标签在预算系统里几乎每个页面都会用到。注意taglib的 uri 别写错,JSTL 1.2 的 core 标签库 uri 是http://java.sun.com/jsp/jstl/core,写错了页面会直接报错。

3.4 预算汇总与导出:用 POI 生成 Excel 报表

答辩时老师最喜欢看的就是导出功能。用 Apache POI 生成 Excel:

public void exportExcel(Integer projectId, HttpServletResponse response) throws IOException { List<BudgetDetail> list = detailMapper.selectDetailByProject(projectId); HSSFWorkbook workbook = new HSSFWorkbook(); HSSFSheet sheet = workbook.createSheet("预算明细"); // 表头 HSSFRow header = sheet.createRow(0); header.createCell(0).setCellValue("科目"); header.createCell(1).setCellValue("金额"); header.createCell(2).setCellValue("备注"); // 数据行 int rowNum = 1; for (BudgetDetail d : list) { HSSFRow row = sheet.createRow(rowNum++); row.createCell(0).setCellValue(d.getSubjectName()); row.createCell(1).setCellValue(d.getAmount().doubleValue()); row.createCell(2).setCellValue(d.getRemark()); } response.setContentType("application/vnd.ms-excel"); response.setHeader("Content-Disposition", "attachment;filename=budget.xls"); workbook.write(response.getOutputStream()); workbook.close(); }

HSSFWorkbook对应.xls格式,XSSFWorkbook对应.xlsx。毕设用 HSSF 就够了,数据量不会超过 65536 行。注意response的 header 必须在getOutputStream()之前设置,顺序反了文件名会乱码。

4. 避坑与排查:SSM+JSP 项目最容易翻车的五个地方

4.1 中文乱码:从数据库到页面的全链路排查

现象:页面上显示的中文变成????或者乱码方块。原因通常有三层:数据库连接 URL 没加useUnicode=true&characterEncoding=utf8、Tomcat 的server.xml没配URIEncoding="UTF-8"、JSP 页面没写pageEncoding="UTF-8"。解决方法是三层都检查一遍,缺哪层补哪层。最稳妥的做法是在web.xml里注册CharacterEncodingFilter,同时数据库 URL 加上编码参数。

4.2 静态资源 404:DispatcherServlet 拦截了 CSS 和 JS

现象:JSP 页面能打开,但样式全没了,F12 看到 CSS 和 JS 请求返回 404。原因是web.xml里DispatcherServlet的url-pattern配了/,所有请求都走 Spring MVC,但 Spring MVC 没有映射静态资源。解决方法是在spring-mvc.xml里加:

<mvc:default-servlet-handler/> <mvc:resources mapping="/static/**" location="/static/"/>

default-servlet-handler会把找不到映射的请求交回给 Tomcat 的默认 Servlet 处理,静态资源就能正常访问了。

4.3 MyBatis 映射文件不生效:路径和命名规范

现象:启动时报Invalid bound statement (not found)。原因通常是 Mapper XML 文件没放在 Maven 的 resources 目录下,或者mybatis-config.xml里没配 mapper 扫描路径。Maven 默认只把src/main/resources下的文件复制到 classpath,如果 XML 和 Java 接口放在一起(src/main/java下),需要在pom.xml的<build>里加<resources>配置把**/*.xml包含进去。

4.4 事务不回滚:@Transactional 失效的常见原因

现象:Service 方法里抛了异常,但数据库数据已经改了,没有回滚。原因通常是:方法不是public的、同类内部方法直接调用(没有走代理)、异常类型不是RuntimeException。Spring 的@Transactional默认只对RuntimeException回滚,如果抛的是Exception需要手动配rollbackFor = Exception.class。

4.5 Tomcat 启动慢或内存溢出:JVM 参数调整

现象:项目启动要等一两分钟,或者跑着跑着报OutOfMemoryError。毕设项目一般不会有大内存需求,但 IDEA 里 Tomcat 默认的 JVM 参数可能偏小。在 Tomcat 配置的 VM options 里加-Xms256m -Xmx512m -XX:PermSize=128m(JDK 8 用-XX:MetaspaceSize=128m)。启动慢通常是因为 Maven 依赖太多,检查pom.xml里有没有引入用不到的包。

5. 打包部署与答辩演示:让项目在老师电脑上也能跑起来

5.1 用 Maven 打 WAR 包并部署到独立 Tomcat

毕设答辩时,老师可能要求你在教室电脑上现场演示。最稳妥的方式是打成 WAR 包,放到独立 Tomcat 的webapps目录下启动。在pom.xml里确认打包方式:

<packaging>war</packaging>

然后执行mvn clean package -DskipTests,在target目录下会生成.war文件。把它复制到 Tomcat 的webapps目录,启动 Tomcat,访问http://localhost:8080/war包名/即可。注意 WAR 包名就是访问路径,建议改成英文短名比如budget。

5.2 数据库迁移:从开发机到演示机的数据准备

演示机的 MySQL 里需要提前建好数据库和表,并且导入初始数据。我一般会导出一份init.sql,包含建表语句和几条测试数据。在演示机上执行source init.sql即可。记得修改项目里jdbc.properties的数据库连接地址和密码,别用开发机的配置。

5.3 答辩演示的流程设计:三分钟讲清楚核心功能

答辩演示时间通常很短,建议按这个顺序走:先登录进系统(展示权限控制),然后新建一个工程项目,接着录入几条预算明细,展示列表页的增删改查,最后点导出按钮生成 Excel 并打开给老师看。整个流程控制在三分钟内,重点突出「数据从页面到数据库再回到页面」的完整闭环。提前准备好测试数据,别现场录入,容易出错。

5.4 源码阅读顺序:拿到一份 SSM 项目后怎么快速上手

如果你拿到的是别人的源码,建议按这个顺序读:先看web.xml了解入口配置,再看applicationContext.xml和spring-mvc.xml了解 Bean 管理和 MVC 配置,然后从 Controller 入手顺着 Service 到 Mapper 走一遍完整调用链,最后看 JSP 页面怎么渲染数据。这样能在半小时内摸清整个项目的结构。我一般还会在本地跑一遍,用 Postman 或者浏览器直接调接口,确认每个功能都能正常工作再去看代码细节。

希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/2 5:58:37

2026年软件测试趋势:AI与云原生测试核心技术解析

1. 2026年软件测试面试趋势与核心能力要求2026年的软件测试领域正在经历一场深刻变革。随着AI测试工具普及率突破60%&#xff0c;测试工程师的职能边界已经从单纯执行测试用例扩展到质量工程全流程。根据最新的行业调研&#xff0c;企业对应聘者的要求集中在三个维度&#xff1…

作者头像 李华
网站建设 2026/11/2 5:58:18

昇腾CANN Toolkit:AIGC开发者的高效工具库

1. CANN Toolkit仓库概述&#xff1a;AIGC开发者的效率引擎第一次接触CANN Toolkit仓库时&#xff0c;我正为一个图像生成项目的推理性能优化焦头烂额。这个由昇腾社区维护的工具集合&#xff0c;就像突然出现的多功能工具箱——它不仅包含了模型转换、性能分析等基础工具&…

作者头像 李华
网站建设 2026/11/2 5:58:15

Kafka核心概念与实战部署指南

1. Kafka是什么&#xff1f;为什么你需要了解它我第一次接触Kafka是在2016年&#xff0c;当时公司需要处理每天上亿条的用户行为数据。传统数据库已经无法承受这样的写入压力&#xff0c;经过多方调研&#xff0c;我们最终选择了Kafka作为数据管道。六年过去了&#xff0c;Kafk…

作者头像 李华
网站建设 2026/11/2 5:58:12

DeepSeek Harness桌面端实战:Electron+Python本地AI工作流搭建

1. 项目概述&#xff1a;这不是一个“新发布”&#xff0c;而是一次技术解构的起点 最近刷到一条标题很抓眼球的消息&#xff1a;“DeepSeek Harness 出了桌面端&#xff1f;我把它扒了一遍”。作为长期关注AI工具链落地实践的一线从业者&#xff0c;我第一反应不是点开看热闹…

作者头像 李华
网站建设 2026/11/2 5:58:12

STM32MP257异构多核Ubuntu系统配置与性能功耗调优实践

1. 先摸清这颗芯片的脾气&#xff1a;平台画像与系统选型STM32MP257 这颗片子刚拿到手的时候&#xff0c;我第一反应是“这不是传统意义上的单片机了”。它里面塞了两个 Cortex-A35 核跑 Linux&#xff0c;又留了一个 Cortex-M33 核做实时任务&#xff0c;还带了个算力不低的 N…

作者头像 李华
网站建设 2026/11/2 5:58:12

DeepSeek Harness桌面端架构解析:Electron+Node+Python本地AI工作流

1. 这不是“又一个GPT桌面端”&#xff0c;而是本地AI工作流的真正入口最近朋友圈和几个技术群都在刷“DeepSeek Harness 出了桌面端&#xff1f;”——标题里那个“扒了一遍”特别抓人&#xff0c;不是简单试用&#xff0c;是真动手拆解。我第一时间下载了官方发布的 Windows …

作者头像 李华