ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

基于JSP的记账管理系统毕业设计:部署、源码与答辩全指南

基于JSP的记账管理系统毕业设计:部署、源码与答辩全指南

简介:面向计算机专业毕业生和需要完成JSP课题的开发者,这份基于JSP的记账管理系统毕业设计资料包提供从项目开发到答辩展示的完整支撑,可解决毕业设计缺方案、代码无参考、答辩材料不齐全等问题。压缩包整体约91.24MB,主要包含项目报告、答辩PPT、Java源代码、数据库脚本和部署演示视频:报告为论文写作和系统说明提供范本,PPT覆盖项目背景、功能设计与演示亮点,源代码采用JSP+Servlet分层结构体现MVC思路,数据库脚本内置建库建表及初始数据,部署视频则展示环境配置与运行过程。已有254人学习下载,适合课程设计、毕业设计及个人实战练习。资料包目录结构清晰,便于按需提取各个模块;整套方案围绕用户登录、收支记账、分类管理、统计报表等核心功能展开,配合演示与部署说明,可帮助读者快速理解记账系统的完整实现路径,减少项目起步和答辩筹备中的重复劳动。

1. 基于JSP的记账管理系统毕业设计:解压之后,先分清五样东西

解压之后,大多数人对着文件夹先愣半分钟:项目报告、答辩PPT、源代码、数据库、部署视频,五个东西码得整整齐齐,就是不知道先动哪个。这套基于JSP的记账管理系统毕业设计,本质是一个标准的B/S结构Java Web项目,用JSP做页面视图、Servlet做请求控制、DAO封装数据库操作,配合MySQL库文件和可导入的SQL脚本,覆盖了登录注册、收支流水、分类管理和统计图表这些高频毕设考点。它主要喂给两类人:一类是正在做毕设选题、想把项目快速跑通并且能在答辩现场讲明白的学生;另一类是刚开始练Java Web、需要一套能完整复现的“jsp入门”项目的开发者。下面直接按“看结构、跑环境、读代码、排故障、备答辩”这条路线走完整个落地过程。

2. JSP+Servlet+JavaBean:为什么记账系统是最稳的毕设骨架

2.1 先从一次请求的走向看这套组合

一个基于JSP的记账系统跑起来的请求路径大致是这样:浏览器打开某个JSP页面,页面里的表单提交到Servlet,Servlet调用DAO层的方法,DAO通过JDBC访问MySQL数据库,拿到结果后再把数据塞回request域,转发回JSP渲染成HTML。这条链路短而完整,正好把Java Web课程里最常考的几个知识点全串起来了。

这套组合比纯Servlet写页面舒服在哪儿?JSP天生擅长做展示,可以用EL表达式和JSTL标签在页面里直接遍历集合、输出表单,不需要像纯Servlet那样拼一大段HTML字符串。它又比SpringBoot方案更贴近教学大纲,结构上没有IoC容器、自动配置这些“黑匣子”——你几乎可以打开任何一个类,顺着方法调用把一次请求从头跟到尾。答辩时老师问“讲讲这个MVC分层怎么体现在代码里”,直接指着目录结构说哪一层干了什么,几分钟就能讲清楚,不用解释Spring那一套复杂概念。对多数学校来说,这就是“稳妥”两个字。

在idea新建jsp项目时,新生成的骨架通常自带web.xml或Servlet注解两种路由方式。旧一点的毕设代码大多走web.xml里配Servlet-mapping;新一些的会用@WebServlet注解。这套记账系统里两种写法都有可能出现,读代码前先分清项目用的是哪种,后面找路由才不会满世界翻文件。同样是解析JSP的容器,这个问题也决定了后续能不能顺利部署。

2.2 记账系统的功能地图:小业务带出大考点

记账这个业务有一个难得的好处:需求很轻,人人都能理解,但展开之后又足够覆盖毕设需要的大部分技术点。它不像电商系统那样要处理订单状态机、库存并发,也不像内容管理系统那样要纠结权限粒度。收入、支出、分类、统计、用户,这五件事就是全部。

功能模块对应核心表涉及技术点答辩时可展开的方向
用户注册登录用户表Session会话、Cookie、登录拦截Filter会话保持与安全退出
收支流水管理账单表数据库增删改查、分页查询、表单校验PreparedStatement防SQL注入
分类管理分类表下拉联动、主外键关联一对多表设计
统计报表账单表聚合查询GROUP BY、SUM、DATE_FORMAT按月份/分类输出图表数据
个人信息展示页面用户表JSP+EL取值、头像上传(若有)文件上传与回显

从答辩考核的角度看,记账系统几乎把“基于JSP的毕设选题”里能被问到的东西都占了:数据库设计有相对完整的表结构,业务层有典型的增删改查,展示层有列表和统计图。更关键的是,任何一个功能都可以被答辩老师深入追问,而你不需要补一大堆额外知识。问你“分页怎么做的”,无非就是一个limit两个参数加一个count查询;问你“修改密码安不安全”,只需要交代加密和防注入。

2.3 项目报告和答辩PPT该怎么对照着读

这份包里价值最大的往往不是代码,而是项目报告和答辩PPT,它们直接决定你花在写文档上的时间能不能省下来。常见的做法是:项目报告从头到尾写完背景意义、可行性分析、需求分析、数据库设计、模块设计、测试与总结几个章节,答辩PPT则把这些内容压缩成十五到二十页的演示稿。拿到包之后不要从头到尾看,先建立一个三列对应关系:报告章节、源码目录、数据库表名。

举个例子:报告里“系统详细设计”那一章如果写了“用户登录流程”,那你到源码包里大概率能找到LoginServlet.java或者login.jsp,数据库里相对应有user表;报告画了E-R图,PPT里截了系统截图,那么在WebContent或webroot目录下能找到对应的JSP页面文件。这一步做通了,你在答辩时才能做到老师指到哪、你能讲到哪,而不是背了一堆概念却找不到代码位置。很多人在答辩时翻车,不是没准备,而是讲的和代码对不上。

3. 本地跑通的最小路径:从建库到Tomcat部署的完整步骤

3.1 动手前先把版本对齐,否则后面全是玄学

JSP项目最怕的不是代码写错,而是电脑环境跟项目原本的构建年代不匹配。常见的保守组合是:JDK 1.8、Tomcat 8.5、MySQL 5.7;稍微新一点的是JDK 1.8配Tomcat 9、MySQL 8.x。这里最要命的分歧点在Tomcat版本和MySQL驱动上,这里给出一个对照表。

组件保守选择较新选择关键注意点
JDK1.81.8高版本JDK也能跑老项目,但编译级别要调好
Tomcat8.5.x9.0.xTomcat 10开始javax.servlet被换成jakarta.*,老代码直接404
MySQL5.78.0.x5.x用com.mysql.jdbc.Driver,8.x用com.mysql.cj.jdbc.Driver
MySQL驱动jar5.1.x8.0.x驱动和数据库版本错配会报各种没见过的大红字
构建方式Eclipse直出IDEA+war包没有Maven的项目就靠WEB-INF/lib里的jar活

顺带说一句,如果团队里有人说“nginx 支持jsp吗”,答案是Nginx本身不解析JSP,它只做静态代理和反向代理,所有JSP请求最终都要转发给Tomcat处理。毕设部署阶段不用急着上Nginx,一台Tomcat足够跑通全流程。

3.2 导入数据库:命令行和图形化两种方式都试一遍

源代码压缩包里的SQL文件通常同时包含建库、建表和初始数据。先在命令行里试一次直连,重点是为了确认数据库账号密码可用。打开终端执行:

mysql -uroot -p # 提示输入密码,进入MySQL命令行,接着执行: source D:/path/to/account.sql; show databases;

这段命令的意图是:先用root账号进MySQL,再把SQL文件整体导入。source后面的路径要注意两点:一是目录分隔符统一用正斜杠或者双反斜杠,直接复制的Windows路径常常带单反斜杠,在这儿会报错;二是SQL文件名如果包含空格,需要用反斜杠转义,或者直接改成纯英文短文件名,这类导入问题不属于“数据库同步软件”那种场景,反而最容易被忽略。

如果你习惯图形界面,用Navicat或者DBeaver也可以:新建连接选MySQL,填上主机、端口、用户名密码,然后在连接上右键选“运行SQL文件”,选SQL文件执行完,刷新就能看到表结构。导入后第一件事不是急着启动项目,而是先看表名和代码里列的字段。常见表的命名方式一般是user、bill、category、type这类单词独立命名,少数项目会加前缀,比如t_user、t_bill。打开SQL文件搜索“CREATE TABLE”能看到全部表名,这个清单记下来,后面调试SQL有用。

3.3 数据库连接配置:db.properties里的几个救命参数

老式JSP项目的数据库连接信息一般写在src目录或classes目录下的properties文件里,常见的名字是db.properties、jdbc.properties、db-config.properties,有的项目干脆直接把这个信息写死在DBUtil类里。这套记账系统的常见配置大概是下面这个模样:

jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/jsp_account?useUnicode=true&characterEncoding=utf8 jdbc.username=root jdbc.password=123456

参数说明:driver是驱动类名,如果本地是MySQL 8.x,就改成com.mysql.cj.jdbc.Driver;url后面的3306是MySQL默认端口,如果之前安装时改过端口,这里要跟着改;databaseName(这里写的jsp_account)必须和SQL文件里建的库名完全一致,差一个字母启动后就会报Unknown database。characterEncoding=utf8解决的是中文存储乱码问题,写法也可以写成characterEncoding=UTF-8,注意MySQL 8.x里最好再追加serverTimezone=Asia/Shanghai,否则连接时会因为时区报错。

如果项目里用了连接池,比如DBCP或C3P0,配置里还会多出initialSize、maxActive这类参数,那就是mysql的数据库连接池的常规选项了。毕设答辩时,老师如果问“连接池和直接DriverManager有什么区别”,就用一句话回答:连接池是提前创建好一批连接反复复用,直接DriverManager是每次请求都新建连接再关闭,高并发下性能差距明显。这句话就能接住大多数追问。

3.4 部署到Tomcat:war包和文件夹两种传统姿势

先讲传统jsp项目打包war这一步,因为标题里提到了部署视频,而视频里最常演示的正是把项目war包拷进webapps目录。假如你在Maven项目里,打包命令是:

cd 项目根目录 mvn clean package # 打包完成后,war文件会出现在target目录下 cp target/jsp-account.war /path/to/apache-tomcat-8.5.x/webapps/ # 启动Tomcat /path/to/apache-tomcat-8.5.x/bin/startup.bat

没有Maven的老项目也没关系,多数maven-less的JSP项目里会有项目的WebContent或webroot目录,IDEA可以直接把它打成war:File -> Project Structure -> Artifacts -> 新建Web Application Exploded或Web Application Archive,构建后在out目录里拿到war包。把war放进webapps后,Tomcat启动时会自动解压出一整个项目文件夹,访问路径默认就是war包名。

不建议跳过这条部署路径直接问“为什么我的IDEA里跑不起来”,因为IDEA内置Tomcat插件和独立Tomcat的路径解析规则有细微差别。部署视频存在的意义就是节省这一步的摸索时间,你跟着视频走一遍,再用命令行独立跑一遍,就能把环境上的“玄学”部分去掉。启动完成后,在浏览器输入:

http://localhost:8080/jsp-account/index.jsp

如果看到一个默认页面或者登录页,说明JSP部署链路是通的;如果在Tomcat日志里看到404或找不到类的异常,直接跳到第5章的排查清单,多半是驱动jar或路径问题。

4. 源码走读:登录、记账和统计的代码到底写了什么

4.1 登录模块:Session和Filter是这套系统的命门

记账系统的登录逻辑基本集中在两个Servlet里:一个是LoginServlet,负责校验用户名密码;一个是LogoutServlet,负责销毁会话。最核心的doPost方法长这样:

public class LoginServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); String username = request.getParameter("username"); String password = request.getParameter("password"); User user = new UserDao().findByUsernameAndPassword(username, password); if (user != null) { HttpSession session = request.getSession(); session.setAttribute("loginUser", user); response.sendRedirect("index.jsp"); } else { request.setAttribute("errorMsg", "账号或密码错误"); request.getRequestDispatcher("login.jsp").forward(request, response); } } }

逻辑说明:先设置请求编码,再读取表单里的username和password,调用UserDao查询数据库,查到就把用户对象放进Session,查不到就把错误信息带回登录页。这里的核心设计是Session——后续所有页面判断“有没有登入”都靠session.getAttribute("loginUser")是不是空值来决定。安全方面有两个明显加分点:一是密码不能明文存储,起码要做MD5散列,答辩时主动说“当前是演示版本所以明文存储,改进方案是用MD5加盐”,比被老师指着代码打脸好得多;二是凡是要登录才能访问的页面,都应该过一个Filter,在doFilter里判断Session有没有值,没有就直接跳回login.jsp。

参数说明中,getParameter拿到的是表单里name属性对应的值,如果页面里输入框name写错,这里永远拿到null;sendRedirect是重定向,浏览器地址栏会变,forward是转发,浏览器地址栏不变,两种跳转别混用。

4.2 记账核心:PreparedStatement和分页,最见功力的部分

记账模块的核心是往账单表里插入一条流水,以及按条件查询流水列表。这是整份源码里最值得反复读的部分,因为数据库增删改查就在这十来行里:

public class BillDao { public int insertBill(Bill bill) { String sql = "INSERT INTO bill (user_id, category, amount, remark, bill_date)" + " VALUES (?, ?, ?, ?, ?)"; try (Connection conn = DBUtil.getConnection(); PreparedStatement ps = conn.prepareStatement(sql)) { ps.setInt(1, bill.getUserId()); ps.setString(2, bill.getCategory()); ps.setBigDecimal(3, bill.getAmount()); ps.setString(4, bill.getRemark()); ps.setString(5, bill.getBillDate()); return ps.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); return 0; } } }

逻辑说明:这组代码用的是PreparedStatement,也就是说SQL骨架先预编译,再用setXxx填充占位符。这样做的好处是参数类型、边界都由JDBC处理,可以挡住“拼接字符串”形式的SQL注入。如果源码里用的是Statement加字符串拼接,答辩被直接扣分的概率极高,趁早改成上面这种写法。

分页查询更典型,列表页一般是按时间倒序展示:

public List<Bill> findBillsByPage(int userId, int pageNo, int pageSize) { String sql = "SELECT * FROM bill WHERE user_id = ? ORDER BY bill_date DESC LIMIT ?, ?"; try (Connection conn = DBUtil.getConnection(); PreparedStatement ps = conn.prepareStatement(sql)) { ps.setInt(1, userId); ps.setInt(2, (pageNo - 1) * pageSize); ps.setInt(3, pageSize); ResultSet rs = ps.executeQuery(); // 遍历ResultSet封装成Bill对象,加入List返回 } }

这里两个参数的语义经常被刚上手的人搞反:LIMIT后面的第一个值是偏移量,从第几条开始取,计算方式是(页码-1)乘每页条数;第二个值是每页取几条。想在页面上显示总页数,还要再写一条SELECT COUNT(*) FROM bill WHERE user_id = ?,然后把总记录数除以pageSize向上取整。这段逻辑在代码里搜“pageSize”或者“totalPage”就能找到,没有的话多半是没做分页、列表一把梭,这种代码拿到答辩台上会被追问到怀疑人生。

4.3 统计报表:SQL聚合和图表渲染怎么衔接

统计功能让记账系统区别于普通的增删改查练习。实现思路是:SQL层用GROUP BY和SUM算出支出分类占比或月度收支汇总,再把这些结果放到request域,JSP页面拿到后用JavaScript图表库画成饼图或柱状图。常见的分类汇总SQL长这样:

SELECT category, SUM(amount) AS total FROM bill WHERE user_id = ? AND EXTRACT(YEAR_MONTH FROM bill_date) = ? GROUP BY category ORDER BY total DESC;

参数说明:第一个问号传当前用户ID,第二个问号传YYYYMM格式的月份,比如202505。EXTRACT(YEAR_MONTH FROM bill_date)的作用是从完整日期里抽取出年和月拼成一个整数,这样就不需要先查询再在Java里做字符串处理,SQL端直接把月度分组解决掉。ORDER BY total DESC让占比最高的分类排前面,饼图展示时前几项就是最明显的。

JSP页面的交接点通常在JavaScript里,Servlet把结果的JSON字符串塞到request,或者用一个固定的数据接口比如chartDataServlet返回JSON。前端用ECharts画的时候,核心逻辑是:

var chart = echarts.init(document.getElementById('chart')); chart.setOption({ series: [{ type: 'pie', data: JSON.parse('${categoryData}') }] });

这段JS要意会:categoryData是后端塞进来的一个JSON字符串,字符串里包含了分类名和对应的金额。实际项目里这个JSON生成不要手动拼,用Fastjson或Jackson的toJsonString方法最省事。统计这段是答辩时的“高光环节”,演示时切到图表页,用两个月的数据变化说明“月度环比”,比讲十页概念都有效。

5. 避坑排查:JSP记账系统最容易翻车的四个现场

5.1 数据库连接被拒绝,报Access denied或Unknown database

现象:Tomcat启动不报错,但一打开登录页就蹦出一大段SQLException,里面能看到Access denied for user,或者Unknown database,localhost的连接请求被拒。

原因:这两种报错的根子都在db.properties。Access denied是用户名密码和MySQL里的实际账号对不上,或者账号只允许localhost登录;Unknown database是URL里的库名和SQL文件建出来的库名不一致。还有一种隐蔽情况:SQL文件里自带CREATE DATABASE建库语句,但没执行到那一行之前就报错中断了,导致数据库根本没建出来。

解决:先用命令行手工确认一遍:mysql -uroot -p进库,执行SHOW DATABASES看目标库在不在;再执行USE 库名;再SELECT * FROM bill LIMIT 1确认表结构有没有初始化数据。三关都过,再回过来看properties文件里的URL,把库名、账号、密码逐一对照改对。

5.2 ClassNotFoundException: com.mysql.jdbc.Driver

现象:报错信息里明确告诉你找不到com.mysql.jdbc.Driver这个类,连带着后续的getConnection都会变成null引用。

原因:绝大多数情况是MySQL驱动jar包不在WEB-INF/lib目录里。在IDEA里能看到项目依赖里有jar,但部署到Tomcat时lib目录是空的,或者jar包放在自己电脑的某个工具目录里根本没被拷贝过来。

解决:打开WEB-INF目录,确认lib文件夹存在,把mysql-connector-java的jar放进去,然后在IDEA里重新构建Artifact。注意区分“IntelliJ的External Libraries”和“Tomcat部署后的lib”,后者才是运行时真正被加载的地方。如果用的是Maven项目,检查pom.xml里的MySQL依赖坐标和版本是不是跟数据库配套。

5.3 中文乱码从登录页一直乱到数据库

现象:登录页输入中文名字报错后,页面上显示问号或繁体乱码;从列表窗口往库里插数据,数据库里存的是一堆问号,页面读回来也是乱码。

原因:这个坑通常是三处编码不一致叠加造成的:JSP文件头里没写pageEncoding,导致Tomcat用默认ISO-8859-1读页面;Servlet处理请求时没调用setCharacterEncoding;数据库表字段用的字符集是latin1而不是utf8mb4。三层里任何一层对不上,就会出现乱码全家桶。

解决:挨个堵上。JSP页面第一行加上<%@ page pageEncoding="UTF-8" %>;ServletdoPost开头加setCharacterEncoding("UTF-8");db.properties里URL加characterEncoding=utf8;MySQL建表时把整张表指定DEFAULT CHARSET=utf8mb4。改完如果库里已经写进了乱码数据,把这张表TRUNCATE掉再重新插一遍,别在编程层面纠结历史脏数据。

5.4 Tomcat 10一启动就404,页面全是404或500

现象:自己电脑上装的是Tomcat 10或更新版本,启动没有任何报错,但访问任何一个JSP都是404,有的还会在日志里看到NoClassDefFoundError。

原因:这属于版本兼容问题。Tomcat 10从javax.servlet迁移到了jakarta.servlet包名,老项目里import javax.servlet.http.HttpServlet全部失效。本质上是同一个Servlet API换了一套命名空间,JSP编译时找不到类,后端自然没法返回页面。

解决:如果你手里的代码是基于javax的,最省事是换成Tomcat 9或8.5,不要动代码。如果必须用Tomcat 10,也可以引入迁移工具(比如Tomcat的Migration工具)把javax批量替换成jakarta,但这套操作对毕设项目来说成本高、收益低,不如直接换容器。部署视频里演示用的Tomcat版本,查看视频里的界面标题栏或者conf/目录版本文件就能对上。

6. 答辩前夜:功能自检清单和一个能加分的图表改进

答辩前一夜不要再大改架构了,这时候最该做的是把系统当用户一样从头到尾走一遍。给自己列一张自检表,按顺序点一遍:打开登录页,注册一个新账号,退出,用新账号登录,记一笔收入、记一笔支出,回列表页看这两条流水在不在,改一笔金额,删掉一笔,再退出一次,重新登录验证数据有没有保留。走完这条线,系统最核心的功能就验证完毕了。

一个我反复遇到的情况是:演示环境里数据库是空的,点开统计图表页面只有一片空白。这个坑最好半夜就填上:用自己平时记的几十笔流水,按三个月、六个分类均匀铺进去,金额别是整数,带点小数。这样第二天答辩打开图表页,饼图和柱状图一出来,评委的注意力立刻从“功能有没有”转向“界面还不错”。要是现造数据,请先确认日期格式和bill_date字段对得上,否则聚合SQL查出来还是零。

如果还有余力做一点代码层面的加分,强烈建议优先改一个点:把报表页的统计从“页面上写死数据”改成上面第4.3节那样用SQL聚合+Chart渲染。哪怕后端只查一个分类汇总,也足以在答辩现场展开讲“这条SQL怎么写、为什么用GROUP BY、问号参数怎么传”。这比临时背十个八股概念更有说服力。

另外准备两句杀手锏以备追问:谈到安全就说PreparedStatement解决了SQL注入,Session超时时间在web.xml里配置;谈到数据库就说表结构按第一范式拆了用户、账单、分类三张主表。这两条基本能覆盖比较常见的拔高提问。我当年第一次答辩时,因为没提前往库里灌演示数据,系统首页一片空白,我只能硬着头皮现场点“新增”现编数据,结果金额打错了好几次,那个场面实在狼狈。后来凡是帮朋友看毕设项目,第一句话就是:库里面有半个月以上的流水了吗?所以现在你也别省这一步,把数据铺好,把报表页打开,剩下的就是按流程稳稳讲完。希望帮到你。

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

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进