实验 2:Java Web 核心组件与数据持久化实战¶
实验信息
- 实验学时:4 学时
- 实验类型:综合性
- 截稿时间:第XX 周周X XX:XX
- 核心目标:脱离内存模拟,实现一个基于 Servlet + Filter + JDBC (Druid) + MySQL/openGauss 的真实用户登录系统。
🧪 实验目的¶
- 数据持久化:掌握 JDBC 规范,使用 Druid 连接池 高效访问数据库。
- 核心交互:熟练处理 Request 参数接收与 Response 响应跳转。
- 状态管理:利用 Session 实现用户登录状态的保持与注销。
- 全局管控:使用 Filter 实现全站乱码解决与登录权限拦截。
- AI 赋能:学会使用 AI 生成标准 SQL 语句及 JDBC 工具类代码。
📋 实验前准备¶
- 已完成 实验 1 并熟悉 Git 流程。
- 本地数据库 (openGauss/PostgreSQL) 已启动,并能通过 IDEA Database 面板连接。
- 确保
pom.xml中已引入druid和postgresql依赖。
👣 实验步骤¶
任务一:获取任务代码 (Fork & Clone)¶
- Fork 仓库:
- 访问实验种子仓库:https://gitee.com/javaweb-dev-tech/lab2-login-system
- 点击 「Fork」,将其复制到你的 Gitee 账号下。
- Clone 到本地:
- 将你 Fork 后的仓库 Clone 到 IDEA 中。
- 注意:本项目是一个空骨架,只有目录结构,核心代码需要你填充。
任务二:AI 辅助数据库设计¶
⚡️ AI 结对编程:让 AI 帮你写 SQL
不要手写建表语句,尝试使用 Prompt 让 AI 生成标准 SQL。
- 打开 IDEA 侧边栏的 AI 助手(通义灵码/DeepSeek)。
-
输入以下 Prompt(直接复制):
🤖 Prompt (提示词)
请帮我生成一段 PostgreSQL/openGauss 的建表 SQL。
表名:t_user
字段要求:
1. id: 主键,自增
2. username: 用户名,字符串,唯一,非空
3. password: 密码,字符串,非空
4. nickname: 昵称,字符串另外,请生成 2 条插入测试数据的 SQL,其中一条用户名为 admin,密码为 123。
-
执行 SQL:复制 AI 生成的代码,在 IDEA 的 Database Console 中执行,创建表并插入数据。
📸 截图 1 (提交物)
将数据库表中成功插入数据的界面截图,重命名为 db_data.png,放入 img 目录。
任务三:封装 JDBCUtils 工具类¶
⚡️ AI 结对编程:生成通用工具类
- 在
src/main/resources下新建druid.properties,填入你的数据库账号密码。 - 在
com.example.util包下新建JDBCUtils类。 - 使用 AI 生成代码:
- 在类中输入注释:
// Prompt: 使用 Alibaba Druid 连接池实现一个 JDBC工具类,包含获取连接、获取DataSource、释放资源的方法,读取 druid.properties 配置 - 等待 AI 生成代码并采纳。
- 在类中输入注释:
- 人工审查:检查 AI 生成的代码是否使用了
DruidDataSourceFactory,路径读取是否正确。
任务四:实现 DAO 与 Servlet 核心逻辑¶
此步骤需要你结合课件手动编码(可适当参考 AI,但需理解逻辑)。
- 编写 UserDao:
- 实现
User login(String username, String password)方法。 - 要求:必须使用
PreparedStatement防止 SQL 注入。
- 实现
- 编写 LoginServlet (
/login):- 接收表单参数。
- 调用 DAO 验证。
- 成功:存入 Session (
currentUser) -> 重定向到/index.jsp。 - 失败:存入 Request (
msg) -> 转发回/login.jsp。
- 编写 LogoutServlet (
/logout):- 销毁 Session -> 重定向回登录页。
📸 截图 2:在
LoginServlet中使用了req.getSession()的代码片段截图,重命名为session_code.png。
任务五:配置“安保系统” (Filter)¶
系统现在不安全,任何人都能直接访问 /index.jsp。我们需要加把锁。
- 创建 AuthFilter:拦截路径配置为
/*。 - 编写拦截逻辑:
- 放行白名单:如果请求的是
/login.jsp,/login(Servlet), 或/css/资源,直接chain.doFilter()。 - 检查 Session:获取
currentUser。 - 判断:
- 有人(已登录)-> 放行。
- 没人(未登录)->
resp.sendRedirect("/login.jsp")。
- 放行白名单:如果请求的是
📸 截图 3:未登录状态下,直接在浏览器地址栏输入
http://localhost:8080/index.jsp,被强制跳转回登录页的效果截图(保留浏览器地址栏),重命名为filter_test.png。
🚀 挑战任务 (Optional - 加分项)¶
如果你基础较好,请尝试完成以下任意一项挑战,并在 README 中注明:
- 挑战 A:密码加密 (Security)
- 痛点:数据库存明文密码是违规的。
- 任务:在注册或预设数据时,使用
MD5或BCrypt对密码加密。登录时,将输入的密码加密后再与数据库比对。
- 挑战 B:记住我 (Cookie)
- 痛点:每次关浏览器都要重登。
- 任务:登录成功时,创建一个存活 7 天的 Cookie 存储用户名。再次访问登录页时,自动回填用户名。
- 挑战 C:跨域支持 (CORS Filter)
- 任务:新建一个
CorsFilter,允许前端(如 Vue/React)跨域调用你的接口。
- 任务:新建一个
💾 作业提交¶
1. 完善 README¶
打开 README.md,填写个人信息,并用一句话总结:
- JDBC 中
PreparedStatement相比Statement最大的优势是什么? - 在本项目中,
Filter起到了什么作用?
2. Git Push¶
3. 最终核验¶
- Gitee 仓库中包含你的完整代码。
img文件夹下有db_data.png,session_code.png,filter_test.png三张截图。
❓ 常见问题 (FAQ)¶
Q: 数据库连接报错 "Connection refused"?
A: 检查
druid.properties里的 url 端口是否正确(openGauss 默认可能是 5432 或 26000),以及数据库服务是否已启动。
Q: 页面中文乱码?
A: 检查是否创建了
EncodingFilter并强制设置了UTF-8。
Q: 登录成功了,但是 Session 里取不到值?
A: 检查
LoginServlet里存 Key 的名字(如"user")和index.jsp里取 Key 的名字是否完全一致(大小写敏感)。