去年接了一个课程设计,题目就是“智能家居门户网站”,当时第一反应是这玩意儿不都烂大街了吗,随便找个Spring Boot加Vue的模板改改交差就行。但真拆开需求一看,要求限定在JSP这一套技术栈里,还得带完整源码、数据库脚本、调试部署说明,这就不是简单搬模板能糊弄过去的事了。
做完之后回头再看,我反而觉得这个题目选得挺有意思。JSP虽然听起来老,但它恰好能帮你把Web开发最底层的那些逻辑彻底摸透:页面怎么渲染、请求怎么流转、Session怎么维持、SQL怎么拼接。以前用Spring Boot写东西,注解一标、依赖一拉,什么都给你安排好,反而不知道底层发生了什么。这个项目做完,我把Servlet生命周期、JDBC连接管理、Filter过滤器这些概念全盘活了。
这篇文章我就把这套系统的完整实现过程、数据库设计思路、调试部署的坑和后续改造方向全部写出来,适合正要做课设、毕设,或者纯粹想补一补JSP/Java Web基础的同学参考。项目本身不复杂,但牵扯到的知识点密度很高,吃透了很值。
1. 智能家居门户到底要做什么——先想清楚业务再动手写代码
很多同学拿到题目就开始建表写页面,写到一半发现逻辑乱套。我习惯先把业务理清楚,把用户是谁、要干什么、数据怎么流转都画明白,再碰代码。
1.1 这个系统解决的真实生活场景
智能家居门户网站,本质上是一个远程控制与状态可视化的入口。我给它定义了三类核心用户:管理员、家庭成员、访客。
- 管理员:负责管理系统里的所有设备,比如添加一个新买的智能灯泡、删除已经淘汰的旧插座、配置场景模式。管理员还可以管理家庭成员的账号,分配控制权限。
- 家庭成员:是日常使用最多的角色。早上出门前看一眼今天家里的温湿度,下班路上提前打开空调,用app或者网页把客厅的灯光调成暖色调,这些都是成员的基本操作。
- 访客:权限最低,一般只能看到房屋公共区域的状态信息,比如客厅温度、大门是否关闭,不能操作任何设备。这适合临时给保姆、钟点工或者来访的亲戚开个只读权限。
搞清楚角色之后,核心业务流程就很清晰了。我整理成了一张简单的表格:
| 模块 | 功能点 | 涉及角色 | 数据流转 |
|---|---|---|---|
| 用户管理 | 登录、注册、权限控制 | 管理员、成员、访客 | 用户表 + Session会话 |
| 设备管理 | 添加、删除、修改、状态切换 | 管理员操作、成员使用 | 设备表 + 状态表 |
| 场景控制 | 一键离家/回家/睡眠模式 | 管理员配置、成员使用 | 场景表 + 关联表 |
| 环境监测 | 温湿度、光照、空气质量展示 | 所有人可见 | 环境数据表 |
| 日志审计 | 记录谁在什么时候做了什么 | 管理员 | 操作日志表 |
1.2 为什么限定用JSP而不是前后端分离
评论区肯定有人会问,都2024年了,为什么还抱着JSP不放手?说实话,如果让我给公司做产品,我也不会上JSP。但作为一个教学型项目,JSP的定位恰好是其他技术栈替代不了的。
JSP最宝贵的地方在于,它把“后端数据”和“前端页面渲染”直接塞在同一个文件里。你写一段<%Java代码循环取出设备列表,然后用HTML拼出一个表格,这个过程的因果关系极其直观——你一眼就能看见数据库里的行是怎么变成浏览器上的像素的。而前后端分离之后,前端是Vue的v-for,后端是JSON,中间还有跨域、Token、接口联调,链路拉得太长,对初学者来说根本没法形成完整的认知闭环。
所以我给这个项目定的基调是:技术不求新,但要求每一步都吃得透。JSP + Servlet + JavaBean的经典MVC组合,加上MySQL存储数据,就是最直白、最不容易出错的方案。等这套东西跑通了,你再去看Spring Boot,会发现理解成本断崖式下降。
1.3 需求拆分与工作量评估
拿到题目之后,我只花了半天就确定了自己的交付清单:
- 一套完整的Java Web工程源码,结构按MVC分层
- 完整的MySQL建库建表脚本,包含测试数据
- 一套可直接运行的调试部署文档
- 至少6个核心功能页面:登录、设备列表、设备详情、场景控制、环境监测、用户管理
这个量级的工作量,一个人正常开发,大概两到三个全天就能全部搞定。如果只是照着我这个思路走,速度还能更快。下面我按模块把实现细节逐一展开。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术栈选型与环境搭建——每一步选择背后都有原因
这个项目虽然叫JSP开发,但真正写起来,里面涉及的不仅是JSP一门前端技术。一套完整可运行的工程,至少包括页面渲染、后端控制、数据持久化、数据库管理、开发调度等多个环节。我详细说一下这套技术组合是怎么搭起来的,以及每一步为什么要选它。
2.1 技术栈清单及各层职责
| 层级 | 技术选型 | 职责说明 |
|---|---|---|
| 前端页面 | JSP + CSS3 + JavaScript + jQuery + Ajax | 页面结构、样式、用户交互与局部刷新 |
| 后端控制 | Servlet | 接收请求、调用业务逻辑、控制跳转 |
| 业务逻辑 | Java Bean(普通类) | 封装设备控制、温湿度计算、用户校验等业务规则 |
| 数据访问 | JDBC + DBCP连接池 | 数据库的连接与增删改查操作 |
| 数据存储 | MySQL 5.7 | 存储用户、设备、场景、环境数据、日志 |
| 服务器 | Tomcat 9.0 | 运行Servlet与JSP的容器 |
| 开发工具 | IDEA或Eclipse + Navicat + Maven(可选) | 编写代码与数据库调试 |
这个搭配的语言逻辑是:JSP只负责展示、Servlet只负责调度、JavaBean只负责业务逻辑、JDBC只负责访问数据库。每一层的职责都极其单一,排查问题时定位很精准。比如页面上数据不显示,你只需要检查两种情况:是Servlet没有把数据放到request里,还是JSP页面里取数据的时候写错了属性名。
2.2 为什么引入连接池而不直接用DriverManager
很多教材里教的是用Class.forName("com.mysql.jdbc.Driver")加DriverManager.getConnection()来连接数据库。这种写法在小项目里能跑,但致命问题在于每次数据库操作都要创建一次物理连接,用完了再断开。在并发量稍微上来一点或者页面刷新频繁的情况下,数据库会因为上下文的反复创建销毁而负载飙高,页面响应速度也会有肉眼可见的卡顿。
我在这里用DBCP连接池来解决这个问题。连接池的核心原理,就是预先创建一批数据库连接,放到一个池子里,谁需要就直接从池里拿,用完了再还回去,而不是真正关闭。这样数据库连接对象的创建只做一次,后续所有请求都复用这一批连接,性能提升是非常明显的。
用DBCP只需要在src目录下放一个dbcp.properties配置文件,然后在Java代码里用BasicDataSourceFactory创建数据源。配置如下:
properties复制# dbcp.properties 连接池配置文件
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/smart_home?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
username=root
password=123456
# 初始连接数
initialSize=5
# 最大活动连接数
maxActive=20
# 最大空闲连接数
maxIdle=10
# 最小空闲连接数
minIdle=5
# 获取连接的最长等待时间(毫秒)
maxWait=5000
然后在工具类DBUtils.java里初始化连接池:
java复制import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.commons.dbcp2.BasicDataSourceFactory;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
public class DBUtils {
private static DataSource dataSource = null;
static {
try {
InputStream is = DBUtils.class.getClassLoader().getResourceAsStream("dbcp.properties");
Properties props = new Properties();
props.load(is);
// 根据配置文件创建数据源
dataSource = BasicDataSourceFactory.createDataSource(props);
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException {
// 从连接池中取一个连接
return dataSource.getConnection();
}
}
注意看第5行到第9行的配置,maxWait=5000的意思是:如果连接池里的连接全被占用,新的请求最多等5秒,超出直接报错。这个参数很关键,它能防止某一个请求长时间占用连接导致整个系统假死。
2.3 Tomcat环境部署与工程目录结构
环境我踩过一次比较浪费时间的坑,就是Tomcat的目录权限问题。在Linux或Mac上,如果你把Tomcat解压到了系统目录(比如/usr/local/),启动时经常会碰到Permission denied。我当时搞了十分钟没反应,最后在终端敲ls -l一看,发现bin目录下根本没有可执行权限。解决办法很简单:
bash复制# 给Tomcat目录赋予读写执行权限
chmod -R 755 /Users/你的用户名/apache-tomcat-9.0.x
