网站3天免输入登录页面编程(含用户注册、找回密码与可交互粒子背景)

网站3天免输入登录页面编程(含用户注册、找回密码与可交互粒子背景)

一、引言

本博客源于《Web编程技术》课程实验六——“网站3天免输入登录页面编程”。实验要求实现一个完整的用户认证系统:用户登录成功后,保存用户名和密码(Cookie,有效期3天),3天内再次访问自动完成登录;超过3天则需重新输入;同时需包含用户注册、密码强度检测、找回密码、管理员后台管理以及动态粒子背景交互等功能。我们在实验五模块化设计的基础上进一步扩展,将项目拆分为32个功能单一的文件,并实现了“碰撞3次消失、点击生成新粒子”的可交互Canvas粒子系统。本文将完整分享项目结构、核心代码、部署过程及小组分工,所有代码均来源于实验报告并包含详细注释。


二、目录


1. 实验要求

编写网站的登录页面,要求能保存用户登录成功时输入的用户名及密码信息,当同一用户3天内再次登录网站首页时,能自动读取之前保存的用户信息判断身份是否合法,如果合法自动完成登录。如果当同一用户超过3天再次登录网站首页时,则需要重新输入用户名及密码进行身份验证,通过验证方能登录并显示欢迎信息。否则提示:身份验证失败,必须重新输入输入。

扩展要求

  • 用户注册(密码长度≥8,包含大写、小写、数字、特殊字符中的至少三类,实时提示强度)。
  • 修改个人资料(密码、邮箱、电话),修改成功后清空Session要求重新登录。
  • 找回密码(通过注册邮箱和电话)。
  • 管理员账号(fzy / Jmu123456,密保 202421336050),登录后以表格形式查看并删除所有注册用户。
  • 所有输入框禁止空格和换行符。
  • 动态粒子背景:粒子碰撞3次后消失,点击页面任意位置生成新粒子。

2. 项目目录结构与设计思想

项目根目录为 task6,在实验五基础上增加了用户注册、文件存储、管理员管理、找回密码等模块,前端粒子系统升级为“碰撞计数+点击生成”。所有 JSP 文件采用 UTF-8 编码,公共 Java 方法统一放在 common/ 文件夹,样式与脚本同样按功能拆分。目录树如下:

task6/
├── index.jsp                     # 登录主页(含自动登录检查)
├── autoLoginCheck.jsp            # 自动登录逻辑
├── loginProcess.jsp              # 登录处理
├── register.jsp                  # 用户注册
├── registerProcess.jsp           # 注册处理
├── account.jsp                   # 个人中心
├── updateProcess.jsp             # 修改信息处理
├── forgot.jsp                    # 找回密码
├── forgotProcess.jsp             # 找回密码处理
├── admin.jsp                     # 管理员界面
├── adminDelete.jsp               # 删除用户处理
├── logout.jsp                    # 退出登录
├── common/                       # 公共函数模块(10个文件)
│   ├── fileReadAll.jsp           # 读取User-Information.txt
│   ├── fileAddUser.jsp           # 添加用户
│   ├── fileUpdateUser.jsp        # 更新用户信息
│   ├── fileDeleteUser.jsp        # 删除用户
│   ├── userValidate.jsp          # 验证用户名密码
│   ├── adminCheck.jsp            # 判断管理员及密保
│   ├── passwordComplexity.jsp    # 密码复杂度校验
│   ├── inputSanitize.jsp         # 禁止空格换行
│   ├── findUserByEmailPhone.jsp  # 通过邮箱电话查找用户
│   └── cookieHelper.jsp          # Base64编解码
├── css/                          # 样式表
│   ├── base.css                  # 全屏布局、画布定位
│   ├── glass.css                 # 玻璃拟态卡片
│   ├── form.css                  # 表单与按钮样式
│   └── message.css               # 提示消息样式
└── js/                           # 前端脚本(11个文件)
    ├── canvas-setup.js           # 画布初始化
    ├── mouse-tracker.js          # 鼠标追踪
    ├── particle-class.js         # 粒子类(含碰撞计数器)
    ├── collision.js              # 碰撞检测(每次碰撞计数器+1)
    ├── renderer.js               # 动画循环、过滤、点击生成
    ├── show-password.js          # 登录页显示密码按钮
    ├── page-init.js              # 错误清空表单 + 管理员密保弹窗
    ├── password-strength.js      # 密码强度实时检测
    ├── password-match.js         # 确认密码匹配提示
    ├── register-validate.js      # 注册表单前端校验
    └── account-validate.js       # 个人中心修改表单校验

设计思想

  • 模块化:每个文件功能不超过2个,高度内聚。
  • 免登录:使用 Cookie 存储 Base64 编码的密码,autoLoginCheck.jsp 在页面加载时自动验证并跳转。
  • 持久化:用户信息存储于 User-Information.txt,使用 synchronized 方法保证并发安全。
  • 安全性:所有输入均过滤空格换行,密码前端+后端双重强度校验,管理员需要密保二次验证。
  • 交互性:Canvas 粒子系统实现碰撞3次消失、鼠标排斥、点击生成新粒子,增强视觉吸引力。

3. 核心业务JSP代码片段

3.1 index.jsp – 登录主页与自动登录检查

index.jsp 顶部通过 <%@ include file="autoLoginCheck.jsp" %> 实现自动登录检测。页面显示玻璃拟态登录表单,包含用户名、密码(带显示/隐藏按钮)、忘记密码链接、注册链接。错误/成功消息通过 request 属性动态渲染。具体代码如下:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ include file="autoLoginCheck.jsp" %>   <!-- 自动登录检查 -->

<%
    String message = (String) request.getAttribute("message");
    String messageType = (String) request.getAttribute("messageType");
    if (message == null) message = "";
    if (messageType == null) messageType = "";
%>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>登录 | 3天免输入系统</title>
    <link rel="stylesheet" href="css/base.css">
    <link rel="stylesheet" href="css/glass.css">
    <link rel="stylesheet" href="css/form.css">
    <link rel="stylesheet" href="css/message.css">
</head>
<body>
<canvas id="particleCanvas"></canvas>   <!-- 粒子背景画布 -->
<div class="glass-container">
    <h2>✨ 用户登录</h2>
    <% if (!message.isEmpty()) { %>
        <div class="form-message <%= "error".equals(messageType) ? "error-msg" : "success-msg" %>"><%= message %></div>
    <% } %>
    <form id="loginForm" action="loginProcess.jsp" method="post">
        <input type="text" name="username" id="username" placeholder="用户名" autocomplete="off" required>
        <div style="position: relative;">
            <input type="password" name="password" id="password" placeholder="密码" autocomplete="off" required>
            <span id="togglePassword" class="password-toggle">👁️</span>
        </div>
        <div class="btn-group"><button type="submit" class="btn btn-submit">登录</button></div>
        <div class="form-footer">
            <a href="forgot.jsp" class="footer-link">🔐 忘记密码?</a>
            <a href="register.jsp" class="footer-link">📝 注册新账号</a>
        </div>
        <input type="hidden" name="adminSecret" id="adminSecret" value="">   <!-- 管理员密保隐藏域 -->
    </form>
</div>
<input type="hidden" id="msgType" value="<%= messageType %>">
<script src="js/canvas-setup.js"></script>
<script src="js/mouse-tracker.js"></script>
<script src="js/particle-class.js"></script>
<script src="js/collision.js"></script>
<script src="js/renderer.js"></script>
<script src="js/show-password.js"></script>
<script src="js/page-init.js"></script>
</body>
</html>

图片1

图3‑1 登录页面初始状态
(深色动态粒子背景,玻璃卡片居中,用户名密码框清晰,底部提供忘记密码与注册链接)

3.2 autoLoginCheck.jsp – 自动登录核心逻辑

纯JSP逻辑页面。当 session 中无用户时,读取Cookie中的用户名和Base64密码,调用 validateUser 验证。普通用户验证成功后刷新Cookie有效期(3天)并跳转至个人中心;管理员则清除Cookie并提示手动登录。核心代码:

<%@ page import="javax.servlet.http.Cookie" %>
<%@ include file="common/userValidate.jsp" %>
<%@ include file="common/adminCheck.jsp" %>
<%@ include file="common/cookieHelper.jsp" %>
<%
    Object u = session.getAttribute("user");
    if (u != null) {
        Boolean isAdmin = (Boolean) session.getAttribute("isAdmin");
        if (isAdmin != null && isAdmin) response.sendRedirect("admin.jsp");
        else response.sendRedirect("account.jsp");
        return;
    }
    Cookie[] cookies = request.getCookies();
    String username = null, pwdEnc = null;
    if (cookies != null) {
        for (Cookie c : cookies) {
            if ("username".equals(c.getName())) username = c.getValue();
            if ("password".equals(c.getName())) pwdEnc = c.getValue();
        }
    }
    if (username != null && pwdEnc != null) {
        String password = decodePassword(pwdEnc);
        if (validateUser(application, username, password)) {
            if (isAdmin(username, password)) {
                // 管理员不允许自动登录,清除Cookie并提示
                Cookie clr = new Cookie("username", ""); clr.setMaxAge(0); clr.setPath("/"); response.addCookie(clr);
                clr = new Cookie("password", ""); clr.setMaxAge(0); clr.setPath("/"); response.addCookie(clr);
                request.setAttribute("message", "管理员请手动登录并输入密保密码。");
                request.setAttribute("messageType", "error");
            } else {
                // 普通用户自动登录成功,刷新Cookie
                Cookie uck = new Cookie("username", username); uck.setMaxAge(60*60*24*3); uck.setPath("/"); response.addCookie(uck);
                Cookie pck = new Cookie("password", pwdEnc); pck.setMaxAge(60*60*24*3); pck.setPath("/"); response.addCookie(pck);
                session.setAttribute("user", username);
                response.sendRedirect("account.jsp");
                return;
            }
        } else {
            // 验证失败,清除Cookie
            Cookie clr = new Cookie("username", ""); clr.setMaxAge(0); clr.setPath("/"); response.addCookie(clr);
            clr = new Cookie("password", ""); clr.setMaxAge(0); clr.setPath("/"); response.addCookie(clr);
            request.setAttribute("message", "自动登录失败,请重新输入用户名和密码。");
            request.setAttribute("messageType", "error");
        }
    }
%>

3.3 register.jsp – 注册页与密码强度检测

注册页包含用户名、密码、确认密码、邮箱、电话。密码框下方实时显示规则提示(大写、小写、数字、特殊字符),通过 password-strength.js 动态更新红/绿颜色,并显示整体强度文字。所有输入框通过 onkeyup 自动过滤空格换行。部分代码:

<div class="password-hint" id="passwordStrengthHint">
    <div>密码规则:长度≥8,且至少包含以下三类:</div>
    <ul>
        <li id="hintUpper" class="invalid">大写字母</li>
        <li id="hintLower" class="invalid">小写字母</li>
        <li id="hintDigit" class="invalid">数字</li>
        <li id="hintSpecial" class="invalid">特殊字符</li>
    </ul>
    <div id="strengthText"></div>
</div>
...
<script src="js/password-strength.js"></script>
<script src="js/password-match.js"></script>
<script src="js/register-validate.js"></script>

图片2

图3‑2 注册页面及密码强度提示
(密码框下方规则列表实时显示满足项,整体强度显示“强度不足(已满足2/4类)”或绿色“合格”)

3.4 admin.jsp – 管理员界面(表格居中显示)

管理员登录后,以表格形式展示所有用户(用户名、邮箱、电话),每行提供删除按钮。表格使用 margin: auto 强制水平居中,玻璃卡片最大宽度放宽。核心样式与表格渲染:

<table class="user-table">
    <thead><tr><th>用户名</th><th>邮箱</th><th>联系电话</th><th>操作</th></tr></thead>
    <tbody>
        <% for(UserInfo u : users.values()){ %>
            <tr>
                <td><%= u.getUsername() %></td>
                <td><%= u.getEmail() %></td>
                <td><%= u.getPhone() %></td>
                <td><button class="delete-btn" onclick="confirmDelete('<%= u.getUsername() %>')">删除</button></td>
            </tr>
        <% } %>
    </tbody>
</table>

4. 动态粒子背景系统

背景粒子系统在实验五基础上增加了“碰撞3次消失”和“点击生成新粒子”的功能。以下为核心代码片段。

4.1 粒子类与碰撞计数器

particle-class.jsParticle 类新增 collisionCount 属性,初始为0,每次碰撞时由 collision.js 增加。

window.Particle = class Particle {
    constructor(x, y) {
        // 支持点击生成时传入坐标
        if (x !== undefined && y !== undefined) { this.x = x; this.y = y; }
        else { this.x = Math.random() * app.canvas.width; this.y = Math.random() * app.canvas.height; }
        const angle = Math.random() * Math.PI * 2;
        const speed = 1.5 + Math.random() * 1.0;
        this.vx = Math.cos(angle) * speed;
        this.vy = Math.sin(angle) * speed;
        this.radius = 3 + Math.random() * 5;
        this.color = `hsla(${Math.random() * 40 + 200}, 50%, 50%, 0.65)`;
        this.collisionCount = 0;   // 新增:碰撞次数计数器
    }
    // ... update() 和 draw() 与实验五相同 ...
};

4.2 碰撞检测与死亡过滤

collision.js 在原有弹性碰撞基础上,每次碰撞使双方 collisionCount 加1。

function handleCollisions(particles) {
    // ... 碰撞检测循环 ...
    if (dist < minDist) {
        // ... 交换速度、修正位置 ...
        a.collisionCount++;
        b.collisionCount++;
    }
}

renderer.js 的动画循环中,每一帧过滤掉 collisionCount >= 3 的粒子:

function animate() {
    // ... 施加鼠标力、更新位置、碰撞检测 ...
    particles = particles.filter(p => p.collisionCount < 3);
    // ... 绘制剩余粒子及连线 ...
}

4.3 动画循环与点击生成新粒子

监听画布 click 事件,在鼠标点击位置生成一个 collisionCount=0 的新粒子并加入数组。

app.canvas.addEventListener('click', (e) => {
    const rect = app.canvas.getBoundingClientRect();
    const scaleX = app.canvas.width / rect.width;
    const scaleY = app.canvas.height / rect.height;
    const clickX = (e.clientX - rect.left) * scaleX;
    const clickY = (e.clientY - rect.top) * scaleY;
    particles.push(new Particle(clickX, clickY));
});

图片3

图4‑1 粒子背景交互效果
(彩色粒子随机运动、碰撞,鼠标推开粒子,连线半透明,点击生成新粒子)


5. 公共函数模块(common/)

common/ 目录下共10个文件,提供所有后端公共方法。例如:

  • fileReadAll.jsp:定义 UserInfo 类,提供 getAllUsers(ServletContext) 读取 User-Information.txt 文件,返回 Map<String, UserInfo>。使用 synchronized 保证并发安全。
  • fileAddUser.jspaddUser(UserInfo, ServletContext) 检查用户名是否重复及是否为管理员保留信息,然后追加写入文件。
  • userValidate.jspvalidateUser(ServletContext, username, password) 调用 getAllUsers 比对,同时硬编码管理员账户。
  • passwordComplexity.jspisPasswordComplex(password) 判断长度≥8且包含三类字符。
  • inputSanitize.jspcontainsSpaceOrNewline(str) 检查空格、制表符、换行符。
  • findUserByEmailPhone.jspfindUserByEmailPhone(ServletContext, email, phone) 遍历文件,按邮箱(不区分大小写)和电话精确查找。
  • cookieHelper.jspencodePassword / decodePassword 使用 Base64 编解码。

所有方法均为 public static synchronized(除纯函数外),确保文件操作线程安全。


6. 本地 Eclipse 集成 Tomcat 部署与运行

步骤1:创建动态 Web 项目
Eclipse JEE → FileNewDynamic Web Project,项目名称 task6,Target Runtime 选择 Apache Tomcat 9.0,勾选 Generate web.xml deployment descriptor

步骤2:导入项目文件
WebContent 下创建 common/css/js/ 文件夹,将所有 JSP、CSS、JS 文件按目录结构放入。确保所有文件编码为 UTF-8。

步骤3:部署并启动 Tomcat
Servers 视图中将 task6 项目添加到 Tomcat,启动服务器。

步骤4:本地浏览器验证
访问 http://localhost:8080/task6/index.jsp,测试以下功能:

  • 注册新用户:填写用户名 testuser,密码 Abc123!@#(强度合格),邮箱 test@example.com,电话 13800138000 → 注册成功,自动跳转登录页并显示绿色提示,根目录生成 User-Information.txt
  • 普通用户登录与3天免登录:登录后进入个人中心,关闭浏览器再打开,自动登录直接进入个人中心(无需再次输入密码)。修改系统时间向后4天,重启浏览器则返回登录页并要求重新输入。
  • 管理员登录:输入 fzy / Jmu123456,弹出模态框要求输入密保 202421336050,正确后进入 admin.jsp,表格显示所有用户,可删除。
  • 找回密码:输入已注册用户的邮箱和电话,显示明文密码。
  • 修改个人信息:个人中心修改邮箱或密码,成功后跳回登录页并提示“修改成功,请重新登录”。
  • 边界条件:注册/登录时输入包含空格的用户名或密码会被拦截,密码强度不足时前端红色提示,后端也返回错误。

图片4

图6‑1 本地注册成功截图
(登录页顶部绿色提示框,登录表单可见)


7. 云端 ECS 服务器部署步骤

步骤1:申请 ECS 实例
阿里云免费试用或购买 Windows Server 2019 实例,配置安全组开放端口:8080(Tomcat)、21(FTP)及被动端口范围 5000-6000。记录公网 IP(如 114.55.150.197)。

步骤2:远程桌面安装 JDK 和 Tomcat
安装 JDK 1.8 并配置环境变量;下载 Tomcat 9.0 解压至 C:\tomcat9,启动 startup.bat,本地浏览器访问 http://localhost:8080 验证。

步骤3:搭建 FTP 服务器
通过“服务器管理器”安装 IIS 及 FTP 服务,创建 FTP 站点,物理路径指向 webapps\ROOT(或新建 task6 文件夹),绑定端口 21,授权 Administrator 读写权限,配置防火墙支持被动模式。

步骤4:导出并上传项目
Eclipse 中右键 task6ExportWAR file,保存为 task6.war。使用 FileZilla 连接 ECS 的 FTP,将 WAR 上传至 webapps 目录。若 WAR 自动解压失败,可采用 ROOT 部署:清空 webapps\ROOT,将本地项目所有内容(包括 WEB-INFcommon/css/js/)复制到 ROOT 文件夹。

步骤5:启动 Tomcat 并公网验证
重启 Tomcat,浏览器访问 http://114.55.150.197:8080/(ROOT 部署)或 http://114.55.150.197:8080/task6/。测试所有功能,确保与本地一致。

图片5

图7‑1 云端公网访问登录页
(浏览器地址栏显示 http://114.55.150.197:8080/,页面与本地完全一致)

图片7

图7‑2 云端管理员界面
(表格显示所有注册用户,删除按钮可用)


8. 实验小结(分工与感想)

本次实验围绕“网站3天免输入登录页面编程”,小组四人分工协作,完成了功能完整、交互丰富的 JSP Web 应用。以下为每位组员的解题思路与调试过程总结。

5.1 方致沅(负责项目架构设计、服务器端验证逻辑与文件存储模块)
我搭建了项目整体目录结构,完成 autoLoginCheck.jsploginProcess.jspregisterProcess.jspupdateProcess.jsp 以及 common/ 下所有公共函数。在设计自动登录时采用 Cookie 存储 Base64 编码的密码,普通用户自动刷新 Cookie 并跳转,管理员则需手动登录。调试中遇到的最大问题是:当 Cookie 中存在无效信息时,页面因 return 语句导致空白。我将 autoLoginCheck.jsp 中的 return 改为重定向到 account.jspadmin.jsp 解决。文件读写使用 synchronized 同步,并通过 ServletContext.getRealPath("/") 获取真实路径,确保云端部署也能正确读写。

5.2 王鑫杰(负责前端交互优化、密码强度检测与表单校验)
我负责所有前端交互模块:password-strength.jsshow-password.jsregister-validate.jsaccount-validate.js 及 CSS 适配。实现密码强度检测时,定义了 checkPasswordStrength 函数,实时更新规则提示列表,并用红/绿色区分是否满足。个人中心修改密码时强度提示函数 updatePasswordStrengthHint 未定义,我在 password-strength.js 中补充该全局函数并在 account.jsp 中调用。显示密码按钮采用点击后切换 typetext,1秒后自动恢复,并清除定时器避免异常。所有表单均前后端双重验证,增强了安全性。

5.3 李润哲(负责Canvas动态粒子背景与鼠标交互系统)
我将实验五的粒子系统升级为“碰撞3次消失 + 点击生成新粒子”。在 particle-class.js 中新增 collisionCount 属性,collision.js 每次碰撞使双方计数器 +1,renderer.js 每帧过滤掉 collisionCount >= 3 的粒子,并监听画布 click 事件生成新粒子。调试中粒子数量不断增长导致性能下降,我通过 filter 及时移除死亡粒子,限制初始50个,最终保持总数稳定。碰撞黏连问题通过增加位置重叠修正代码并跳过“正在远离”的粒子对解决。鼠标推开粒子的效果为网站增添了科技感。

5.4 康奕彬(负责管理员功能、找回密码模块及云端ECS部署)
我负责 admin.jspadminDelete.jsp 及找回密码模块(forgot.jspforgotProcess.jsp)。管理员界面以表格展示所有用户并提供删除按钮,调试时表格无法居中,我给表格添加 margin: 0 auto 并设置 width: auto,同时为容器设置 align-items: center 解决。找回密码通过 findUserByEmailPhone.jsp 根据邮箱和电话匹配用户并明文显示密码。云端部署时,我安装 JDK 和 Tomcat,配置安全组开放8080端口,由于 WAR 自动解压失败,我采用“ROOT 部署”方案:清空 webapps/ROOT,将本地项目所有内容复制进去,并添加 WEB-INF/web.xml 指定欢迎文件。同时搭建 IIS FTP 服务,实现 DreamWeaver 无缝上传。公网访问验证所有功能均正常。

5.5 团队协作总结
我们延续了前五次实验的分工协作模式,通过微信群实时同步进度。方致沅的 common/ 公共函数库为全组提供了统一接口;王鑫杰的前端校验脚本被所有表单复用;李润哲的粒子背景为网站增添了生动性;康奕彬的云端部署方案彻底解决了上下文路径问题。当出现表格居中失败、密码强度函数未定义等问题时,大家通过远程协助快速定位并解决。通过本次实验,我们掌握了 JSP 内置对象、Cookie 免登录、文件持久化、Canvas 动画以及云服务器部署的完整流程,为后续课程设计积累了宝贵经验。


附录
《Web编程技术》余元辉,清华大学出版社,2024.8
《JSP设计》(第三版),Hans Bergsten主编,林琪、朱涛江翻译 O'Reilly Media,Inc 2024年。

posted @ 2026-05-17 10:50  fangzhiyuan  阅读(11)  评论(0)    收藏  举报