
简介一套基于Java Servlet与JSP技术栈开发的房屋租赁管理信息系统采用B/S前后台架构前端使用JSP、CSS、JavaScript、jQuery与Ajax实现轮播图、信息检索等交互后端以Servlet处理业务逻辑配合MySQL存储数据可在Eclipse或IDEA中运行环境基于JDK1.8与Tomcat7及以上。系统包含管理员与普通用户两种角色前台提供会员登录注册、密码找回、新闻中心、出租求租求购信息发布与检索、留言板等功能后台涵盖新闻资讯、会员、留言板、滚动公告、出租/出售/求租/求购信息、预定定金合同、收付款、房屋及销售租金报表、管理员与登录日志等管理模块业务流程完整模块边界清晰适合用作Java Web课程设计或毕业设计参考。资源包共681个文件压缩后约2.6MB主要包括JSP动态页面、Java源码与class字节码、JS脚本、CSS样式、GIF图片以及SQL数据库脚本等目录结构清晰解压导入后即可运行与二次开发。目前已有262人学习浏览适合需要完整前后台源码和后台报表功能的开发者直接下载参考。1. 基于 Servlet 的房屋租赁系统这套含前后台的毕设源码能直接跑出什么做 Java Web 方向毕设或课程设计房屋租赁管理系统是出现频率最高的题目之一。基于 Servlet 的这套房屋租赁管理信息系统前端用 JSP 配合 CSS、JavaScript、JQuery 和 Ajax 做交互后端用纯 Servlet 处理业务数据落在 MySQL开发环境用 Eclipse跑在 Tomcat 7 及以上版本。它的完整度比大多数课程设计高前台给普通用户提供注册登录、忘记密码、信息检索、出租出售浏览、求租求购发布和留言板后台给管理员提供新闻管理、会员管理、公告管理、出租出售求租求购信息管理还带预定、定金、合同、收付款和两类统计报表。适合两类人一是正在为毕设选题发愁的学生想找个结构完整、能在答辩前快速跑起来还能讲清楚的工程二是想练 ServletJSP 原生 Web 开发、不想一上来就套 Spring Boot 的入门者。这套东西技术不算新但分层清楚、模块齐全二次开发空间大值得下载后完整拆一遍。2. 技术栈与工程结构ServletJSPMySQL 的分层逻辑以及 JDK、Tomcat 的版本搭配2.1 为什么这套系统选 ServletJSP 而不是直接上 Spring很多人拿到这套系统会问一句都什么年代了怎么还在用 Servlet 写后端答案是这套系统的定位是教学和毕设不是生产级微服务。Servlet 是 Java Web 的根Spring MVC 的 DispatcherServlet 本质上就是包了一层壳的 Servlet。你把这套系统的请求链路捋顺再去理解 Spring MVC 的 HandlerMapping、Controller、ViewResolver基本都是逐一对应的关系。这也是为什么很多 Java 面试题里 Servlet 生命周期、doGet 和 doPost 的区别仍然是必考点——底层机制没变。Servlet 的生命周期可以拆成四步容器启动或首次请求时加载 Servlet 类并实例化然后调用 init() 做初始化每次请求由容器分配线程调用 service()service() 再根据请求方法分发给 doGet 或 doPost容器关闭时调用 destroy() 释放资源。这套系统所有后端逻辑都走这条路前端的 JSP 表单提交到 Servlet 的 doPostServlet 调用 DAO 层访问 MySQL拿到结果后用 request.setAttribute 把数据塞回 JSP 渲染或者用 response.sendRedirect 做页面跳转。这里有个很重要的细节容易被初学者忽略Servlet 默认是单实例多线程的。也就是说所有用户请求共享同一个 Servlet 实例实例字段会被并发访问。我拆这套系统源码时专门看过它的 Servlet大部分操作用的是方法内的局部变量没有把用户数据存到实例字段里所以不会出现 A 用户登录状态串到 B 用户头上的问题。你如果二次开发时想在 Servlet 里加个成员变量缓存当前登录用户那就是典型的翻车姿势后面避坑章节我会详细说。JSP 在这套系统里负责显示层本质上是 Servlet 的模板化写法。JSP 第一次被访问时会被容器编译成 Servlet class所以首次打开页面会慢第二次访问就快了。这套系统的前台页面里用了 JQuery 和 Ajax 做局部刷新比如信息检索、轮播图切换交互在原生 Web 项目里算完整的。JSP 里的小脚本和 JSTL 标签混用看起来有点乱但恰好适合拿来学——你能在一套代码里同时看到 Java 控制权、HTML 标签和 EL 表达式三种写法对照着看更容易理解模板渲染是怎么回事。2.2 前后台功能清单与两角色权限边界这套系统的功能划分非常清晰两张表能看明白端角色核心功能前台普通用户会员登录/注册、忘记密码密保问题找回、首页轮播、新闻中心、出租信息、出售信息、求租信息、求购信息、信息检索、会员中心、留言板后台管理员新闻资讯管理/发布、注册会员管理、留言板管理、滚动公告管理/发布、出租信息管理/发布、出售信息管理/发布、求租信息管理、预定信息管理、定金信息管理、合同信息管理、收付款信息、求购信息管理、房屋统计报表、销售租金报表、管理员设置、后台登录日志权限边界分得很清楚普通用户登录后进的是前台会员中心只能维护自己的个人信息、管理自己发布的求租求购信息管理员登录后进后台能看全部会员、全部房源、全部合同和收付款流水。这套系统没有用 Spring Security 或 Shiro 那套权限框架权限控制是靠两个不同的登录入口加上 Session 里的角色标识实现的。常见做法是登录成功后执行 request.getSession().setAttribute(role, admin)后台每个 Servlet 在处理业务前先判断当前 Session 里的角色不是管理员就重定向回后台登录页。这种做法的好处是直观你打断点调一个后台 Servlet 就能把整个权限校验链路看穿。坏处是每个 Servlet 里都有重复的校验代码改权限逻辑时得逐文件改。如果你打算把这套系统当毕设交答辩时能把这个权限模型讲清楚比只会截页面有说服力得多。2.3 环境配置JDK 1.8、Tomcat 7、MySQL 的版本搭配细节环境这块信息来自项目说明我实际复现时做了验证整理成表组件版本要求实际复现备注JDK1.8代码里没用到 9 的新特性1.8 最稳Tomcat7 及以上7.0 / 8.5 / 9.0 都兼容推荐 8.5MySQL5.7 / 8.05.7 省事8.0 必须用 8.x 驱动并处理 SSL开发工具Eclipse / IDEA / MyEclipseEclipse 导入最顺IDEA 需注意打包方式驱动mysql-connector-java5.1.49 配 5.78.0.33 配 MySQL 8.0为什么要求 JDK 1.8 而不是更高版本因为这套系统工程编译级别就是 1.8代码用的语法是泛型、增强 for、集合框架没有任何 JDK 9 之后的新特性。高版本 JDK 也能跑但没必要冒险。Tomcat 要求 7 及以上是因为 Servlet 3.0 规范从 Tomcat 7 开始支持注解web.xml 即使只写 welcome-file 也能正常部署。我实际用的是 Tomcat 8.5 mysql-connector-java 5.1.49 MySQL 5.7没有任何问题。如果你的本机装的是 MySQL 8.0有两个经典坑驱动类名要改成 com.mysql.cj.jdbc.Driver连接串必须带 useSSLfalse 和 serverTimezoneAsia/Shanghai否则启动后访问页面会直接报 SSL 连接错误或时区异常。数据库建库时建议字符集指定 utf8mb4、排序规则 utf8mb4_general_ci这套系统里有中文新闻、中文留言和住户姓名建库时用了默认 latin1 的话后面页面全是问号所以初始化数据库这一步就应该把编码固定下来。3. 从导入到上线Eclipse 里把房屋租赁系统跑起来的三步操作3.1 导入 Web 工程并理解目录结构拿到源码包第一步不是急着双击而是先把目录结构看一遍确认它到底是一个完整 Eclipse 工程还是一堆散文件。这两个情况导入方式完全不同。我拆项目的习惯是先看有没有 .project 和 .classpath 这两个隐藏文件有的话直接 Eclipse 里 File Import Existing Projects into Workspace选到源码根目录导入出来就是一个可以运行的 Dynamic Web Project。如果只有 src 和 WebContent 的文件夹没有 .project那就新建一个 Dynamic Web Project再把目录内容对号入座拷进去注意把 WebContent 指认为 Web 根目录。一个标准的原生 Servlet 工程目录大致长这样src/ com.xxx.servlet/ # 处理请求的 Servlet前后台各一套 com.xxx.dao/ # 数据访问层JDBC 操作全在这 com.xxx.entity/ # 实体类对应数据库表 com.xxx.service/ # 业务逻辑层部分操作直接合并进了 Servlet com.xxx.util/ # 工具类DBUtil 数据库连接在这 WebContent/ index.jsp # 前台首页 admin/ # 后台所有管理页面 css/ js/ images/ # 静态资源 WEB-INF/ web.xml # 部署描述文件Servlet 映射和欢迎页都在这建议你把 src 下按包名过一遍搞清楚哪个 Servlet 对应用户的哪个操作。原生 Servlet 项目不像 Spring Boot 用注解把 URL 和 Controller 绑在一起URL 映射全部写在 web.xml 里。打开 web.xml 看一眼 url-pattern比如 /login、/register、/admin/addNews大概就能知道系统的请求面长什么样。这一步不花时间但对后面改代码特别重要——你至少得知道改哪个文件才对得上要找的功能。3.2 数据库初始化导入 SQL 脚本与修改连接配置源码包基本都会带一个 SQL 初始化脚本比如 house_rental.sql。用命令行导入是最直接的mysql -u root -p house_rental.sql导入前先确认你要建数据库名是什么脚本里一般有 CREATE DATABASE 和 USE 语句如果脚本里没写库名就手动先建库再导入CREATE DATABASE house_rental DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;逻辑说明第一条命令让 MySQL 执行脚本里的全部建表语句第二条是手动建库兜底避免脚本里没写建库逻辑导致导入失败。utf8mb4 不是可选项这套系统要存中文utf8 在某些 MySQL 版本下对 4 字节字符支持不完整直接上 utf8mb4 最省心。导入之后把数据库连接配置改成本机的。这套系统的连接信息集中在 DBUtil 工具类里可能叫 DBUtil.java 或 db.properties核心代码大概是这样// DBUtil.java 核心连接代码按本机环境改这里 public class DBUtil { private static final String DRIVER com.mysql.jdbc.Driver; private static final String URL jdbc:mysql://localhost:3306/house_rental ?useUnicodetruecharacterEncodingutf8useSSLfalse; private static final String USER root; private static final String PASSWORD 你自己的密码; }参数说明useUnicodetrue 和 characterEncodingutf8 是配套的保证程序写入数据库的中文不乱码useSSLfalse 关闭 SSL 握手——如果你用的是 MySQL 8.0 和 8.x 驱动这个参数必填否则启动后控制台会刷 SSL 连接报错3306 是 MySQL 默认端口本机改过端口就同步改这里。PASSWORD 改成自己 MySQL 的 root 密码这一步漏了的话后面所有页面打开都会是 500 加空指针异常。3.3 部署到 Tomcat 与启动验证部署有两种方式开发调试用 Eclipse 内置部署最快交付打包用 war 最规范。Eclipse 里右键项目 Run As Run on Server选本地 Tomcat 8.5容器会自动编译并部署。传统 JSP 项目要打包 war 的话在项目根目录执行# 在项目根目录执行把整个 WebContent 打成 war 包 jar -cvf house_rental.war .打包时注意当前目录是 WebContent 的上一级保证 war 包解压后第一层就是 WEB-INF 和 index.jsp。把生成的 house_rental.war 复制到 Tomcat 的 webapps 目录下启动 Tomcat 后它会自动解压部署。启动成功后验证三个入口前台首页http://localhost:8080/house_rental/后台登录http://localhost:8080/house_rental/admin/login.jsp数据库是否通看首页有没有加载出租信息和新闻列表如果首页抛 500先切到 Tomcat 控制台看异常栈绝大多数情况指向 DBUtil 那一行的连接参数。默认管理员账号一般在 SQL 脚本里初始化了常见组合是 admin/admin123登录后台后第一件事去点后台登录日志确认功能链路全通。4. 核心模块拆解找回密码、出租信息发布与房屋统计报表的实现思路4.1 找回密码回答密保问题的校验流程这套系统的忘记密码功能不走邮箱也不走短信用的是密保问题。实现流程拆成三步用户输入会员名Servlet 从 member 表查出该用户预设的密保问题回显到页面用户输入密保答案Servlet 比对答案一致就跳到重置密码页不一致就返回提示。核心代码逻辑如下// 找回密码 Servlet 的核心分支逻辑 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String action request.getParameter(action); String username request.getParameter(username); MemberDao dao new MemberDao(); if (getQuestion.equals(action)) { // 第一步查询密保问题并回显 String question dao.getQuestionByUsername(username); request.setAttribute(question, question); request.getRequestDispatcher(forgot.jsp).forward(request, response); } else if (checkAnswer.equals(action)) { // 第二步校验密保答案 String answer request.getParameter(answer); boolean ok dao.checkAnswer(username, answer); if (ok) { request.getSession().setAttribute(resetUser, username); response.sendRedirect(reset_password.jsp); } else { request.setAttribute(msg, 密保答案不正确); request.getRequestDispatcher(forgot.jsp).forward(request, response); } } }逻辑说明整个流程靠 action 参数区分同一个 Servlet 的多个操作这是原生 Servlet 项目最常见的写法不用 RESTful 风格。getQuestion 分支负责查出密保问题并 forward 回表单页checkAnswer 分支校验答案通过后把用户名写进 Session 再重定向到重置密码页避免把用户名放在 URL 参数里被看到。这个设计有一个注意点重置密码页里必须再次校验 Session 里的 resetUser 是否存在有些人拿到源码后直接在 JSP 里用隐藏域传用户名等于把重置入口敞开给别人属于越权风险二次开发时要补上。4.2 出租信息发布与信息状态流转后台上架一条出租信息前台首页和信息列表页同步展示。核心表 house_info 的字段一般包含标题、户型、面积、月租金、位置、描述、状态0 未租、1 已租、发布时间。管理员在后台表单填完Servlet 把参数封装成 entity 对象DAO 层执行 insert前台 JSP 用循环把列表渲染出来。真正要理清楚的是状态流转这是整套系统业务上最容易被忽略的点。一条出租信息从发布到成交大致经过这样的链路发布未租→ 有用户发起预定预定信息表→ 交定金定金信息表→ 签合同合同信息表→ 收付款收付款表→ 房源状态改成已租。每一步都是独立的数据表之间用 house_id 和 user_id 关联。这块有个业务设计值得注意预定信息表产生预定记录时建议同步把 house_info 的状态从 0 改成 1。我翻过几套同题目的项目不少是把状态留在原地等签完合同才改中间这段空窗期如果有两个用户同时预定同一套房后台上架信息的人又没及时处理就会出现重复预定。改成预定即锁房并发问题就从根上少了一半。4.3 房屋统计报表与销售租金报表的数据聚合报表模块是这套系统后台最有含金量的地方。房屋统计报表按房源类型和租赁状态聚合数量销售租金报表按月、按季度汇总成交金额。这类统计查询的习惯做法是直接在 DAO 层写聚合 SQL把结果集转成 List或统计实体再传给 JSP 渲染表格。销售租金报表的核心 SQL 大致是这样-- 销售租金按月统计报表页面的核心聚合查询 SELECT DATE_FORMAT(pay_time, %Y-%m) AS month, SUM(pay_amount) AS total_amount, COUNT(*) AS deal_count FROM payment_info WHERE pay_status 1 GROUP BY DATE_FORMAT(pay_time, %Y-%m) ORDER BY month DESC;逻辑说明pay_time 是收付款时间pay_status 1 表示已确认收款GROUP BY DATE_FORMAT(pay_time, %Y-%m) 把流水按月份分组SUM 汇总当月租金金额COUNT 统计当月成交笔数ORDER BY month DESC 让最新月份排最前。这套系统报表页没有引入图表库直接输出 HTML 表格。如果你是拿去交作业建议在此基础上引入 ECharts 画柱状图效果会明显提升具体改法在第 6 章给。4.4 预定、定金、合同与收付款的关联设计这几张表围绕一次成交构成完整的业务链。预定信息表记录用户对哪套房源发起了预定、预定时间、预定状态定金信息表记录交了多少定金、交了没有合同信息表记录租期起止、月租金、甲乙双方信息收付款表记录每一笔钱款的方向和金额。它们用业务字段手动关联没建外键DAO 层在读写时维护一致性。要特别注意一个业务区分定金和首期租金是两个概念。定金是预定诚意金签合同时用来抵扣押金或租金属于预付款性质的资金租金是合同生效后按周期收的费用。这套系统把定金和收付款分两张表设计是对的。我拆过不少同题目项目很多把定金硬塞进收付款流水导致报表金额对不上合同金额和实际收款对不齐。答辩时把这条链路讲透比列一遍功能清单更能体现你读懂了这个系统。5. 避坑指南部署房屋租赁系统时最常见的五个问题与排查路径5.1 数据库连接报错SSL 连接错误与驱动版本不匹配现象Tomcat 启动后打开前台首页直接报 communications link failure控制台刷 com.mysql.cj.exceptions 相关的异常或者提示 CLIENT_PLUGIN_AUTH is required。原因本机装的是 MySQL 8.0但工程里用的还是 5.1.x 的旧驱动或者连接串漏了 useSSLfalse 和 serverTimezone。MySQL 8.0 默认开启 SSL旧驱动握手协议不一致直接拒绝连接。解决把 lib 下的 mysql-connector-java 换成 8.0.xDBUtil 里的驱动类改为 com.mysql.cj.jdbc.DriverURL 补全为 jdbc:mysql://localhost:3306/house_rental?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai改完重启 Tomcat。这个也是 MySQL 8.0 用户最常见的第一个拦路虎网上大量报错帖都指向同一个原因。5.2 JSP 页面中文乱码三处编码必须一致现象前台页面中文显示成问号后台发布一条中文新闻存进数据库后再查出来也是乱码。原因页面编码、Servlet 请求编码、数据库字符集三处至少一处不一致。JSP 页面 head 里写了 pageEncoding但如果 Servlet 端没有调 request.setCharacterEncoding(utf-8)表单提交的中文到 Servlet 时就已经解析错了存进去自然是错的。解决在 Servlet 的 doGet 和 doPost 第一行都加 request.setCharacterEncoding(utf-8)检查每个 JSP 的 pageEncoding 统一为 utf-8确认 MySQL 建库用的 utf8mb4。三处统一后从头到尾不会有乱码残留。这个排查顺序要记牢从请求入口到存储端依次核对基本一次定位。5.3 Tomcat 启动报 ClassNotFoundException驱动包没进 lib现象Tomcat 启动时抛 java.lang.ClassNotFoundException: com.mysql.jdbc.Driver或者运行到第一次查数据库时报找不到驱动类。原因mysql-connector-java 的 jar 包被放在了项目根目录或者 src 下面没有进 WebContent/WEB-INF/lib。Eclipse 编译期能通过但 Tomcat 部署时只打包 WebContent 里的内容ClassLoader 运行时找不到驱动类。解决把 jar 包复制到 WebContent/WEB-INF/lib 目录下Eclipse 会自动加入 Build PathTomcat 部署时也会同步打包。复制后右键项目 Refresh重启服务再验证。以后拿到任何含第三方 jar 的原生 Web 工程第一件事就是检查 lib 目录有没有该有的包。5.4 前后台入口 404web.xml 的欢迎页与访问路径现象地址栏输入 http://localhost:8080/house_rental/ 返回 404但输入 index.jsp 能正常打开后台地址不写 admin 目录也打不开。原因web.xml 里没配置 welcome-file或者配置的欢迎文件名和实际文件名不一致。有些版本的源码里首页是 index.jsp但 web.xml 里写成了 index.html自然匹配不上。解决打开 WEB-INF/web.xml确认 welcome-file 里的文件名和 WebContent 根目录下的实际文件一致。后台页面如果放在 admin 子目录路径必须写全比如 /house_rental/admin/login.jsp。改了 web.xml 要重启 Tomcat 才生效这点经常被忽略记得清空 Tomcat 的 work 目录再启动。5.5 Ajax 拿不到数据请求路径、响应格式与编码现象前台信息检索或页面局部刷新区域一片空白F12 打开浏览器开发者工具看到 Ajax 请求返回 404或返回的 JSON 中文乱码。原因JSP 里的 $.ajax 用相对路径当前页面在 admin 子目录时相对路径会被解析成 /house_rental/admin/xxx而 Servlet 映射注册在根目录自然 404。响应乱码则是 Servlet 端忘记设置响应编码。解决Ajax 请求路径统一用绝对上下文路径先在 JSP 头部声明 var ctx %request.getContextPath()%然后请求地址写成 ctx /searchServlet。Servlet 端处理完要执行 response.setContentType(application/json;charsetutf-8)然后再输出 JSON 字符串。这两处改完局部刷新就正常了。6. 二次开发技巧把销售租金报表改造成带时间筛选的可复用模板报表是这套系统里最值得动手改造的模块。原版做的是全量统计页面固定查所有月份。实际使用场景里管理员更关心的是这个月收了多少钱去年三季度成交了几单所以我把报表改造成带年份、月份筛选的可复用模板一个 Servlet 通吃两种统计口径。第一步在 JSP 页面加一个筛选表单提交参数设计成 year 和 month。表单不写死 action用 JavaScript 拼查询参数这样一个表单既能查全年也能查单月。第二步核心是把写死的 SQL 改成带条件参数的动态查询。我用 PreparedStatement 的占位符而不是字符串拼接这套系统没有引入 ORM拼 SQL 是常规操作但拼接用户输入很容易被注入占位符是底线写法-- 销售租金报表带时间筛选的聚合查询 SELECT DATE_FORMAT(pay_time, %Y-%m) AS month, SUM(pay_amount) AS total_amount, COUNT(*) AS deal_count FROM payment_info WHERE pay_status 1 AND (? OR DATE_FORMAT(pay_time, %Y) ?) AND (? OR DATE_FORMAT(pay_time, %m) ?) GROUP BY DATE_FORMAT(pay_time, %Y-%m) ORDER BY month DESC;逻辑说明第一个参数是年份筛选传入空字符串表示不过滤第二个参数是月份筛选同样支持空值。这样一条 SQL 覆盖了查全年查某一年查某一年某月三种场景。对应的 Java 侧用 PreparedStatement 逐个 setString 绑定参数月份参数如果为空就传空串JDBC 不会因为空值报错。第三步把查询结果输出成 JSON 交给前端图表。原版用 JSP 表格直接渲染改造后我先查列表再在前端拼装// 报表页面前端把后端返回的统计结果转成图表数据 $.ajax({ url: ctx /reportServlet?year year month month, type: GET, dataType: json, success: function (data) { var months data.map(function (item) { return item.month; }); var amounts data.map(function (item) { return item.total_amount; }); // 拿到数组后交给 ECharts 初始化柱状图 initChart(months, amounts); } });逻辑说明Servlet 把 List用 Jackson 序列化成 JSON 数组回给前端前端用 map 拆出月份和金额两个平行数组正好对齐 ECharts 的 xAxis 和 series 数据结构。改造完的效果就是后台报表页多了一个筛选条管理员按年选、按月选柱状图实时变化表格同步刷新。从那以后我每次改这类报表模板都强制自己先把 SQL 参数边界写清楚再动页面空字符串就不过滤的写法已经成了固定套路。报表功能的价值不在那张表本身在于它把统计口径和展示形式解耦了你换前端图表库、加导出 Excel 功能都不需要动 SQL。这套系统模块多、结构完整真正花时间拆一遍的话能整理出来的可复用套路远不止报表这一个。希望帮到你。本文还有配套的精品资源点击获取