
在web应用中,用户通过html表单(<form>元素)向服务器提交数据。表单的核心属性包括:
客户端JavaScript验证则是在数据发送到服务器之前,对用户输入进行初步检查。这不仅能提供即时反馈,提升用户体验,还能有效减轻服务器的验证负担。只有当客户端验证通过后,数据才会被发送到服务器进行进一步处理(如服务器端验证、数据库操作等)。
原始代码中存在两个主要问题,导致JavaScript验证通过后无法正确调用Servlet:
在提供的JavaScript代码中,formSubmit.addEventListener("click", ...) 事件监听器在每次点击提交按钮时都会执行 e.preventDefault()。e.preventDefault() 的作用是阻止事件的默认行为。对于表单提交按钮而言,其默认行为就是提交表单。因此,无论客户端验证结果如何,表单的默认提交行为都被无条件阻止了,导致数据永远无法发送到 LoginServlet。
formSubmit.addEventListener("click", (e) => {
    // ... 验证逻辑 ...
    if (Rno == null || Rno == "" || Password.length < 7) {
        alert("Please enter a Room No or your password is incorrect");
        setTimeout(function () {
            window.location.reload();
        }, 5000);
    }
    e.preventDefault(); // 问题所在:无条件阻止了表单提交
})当尝试使用 document.location.href = 'LoginServlet'; 进行跳转时,浏览器会发起一个HTTP GET请求。然而,LoginServlet 中只实现了 doPost 方法来处理POST请求,没有实现 doGet 方法。当服务器收到一个POST-only Servlet的GET请求时,根据HTTP协议规范,会返回HTTP 405 Method Not Allowed 错误,表示请求的HTTP方法不被允许。
立即学习“Java免费学习笔记(深入)”;
public class LoginServlet extends HttpServlet {
    // ...
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 实现了doPost方法
    }
    // 没有实现doGet方法
}解决上述问题的关键在于有条件地阻止表单的默认提交行为。只有当客户端验证失败时,才调用 e.preventDefault()。如果验证通过,则允许表单的默认提交行为发生,让浏览器按照 <form method="post" action="LoginServlet"> 的定义向 LoginServlet 发送POST请求。
建议监听表单的 submit 事件而非按钮的 click 事件,因为 submit 事件能捕获所有表单提交方式(例如用户按回车键)。
<script>
    // 获取表单元素,而不是提交按钮
    const loginForm = document.querySelector(".loginForm"); 
    loginForm.addEventListener("submit", (e) => { // 监听表单的submit事件
        const Rno = document.getElementById("Rno").value;
        const Password = document.getElementById("pass").value;
        if (Rno === null || Rno.trim() === "" || Password.length < 7) {
            alert("请输入房间号,或密码长度不正确(至少7位)。");
            // 仅在验证失败时阻止表单的默认提交行为
            e.preventDefault(); 
            // 移除不必要的页面重载,因为它会清除用户输入,影响用户体验
            // setTimeout(function () { window.location.reload(); }, 5000); 
        }
        // 如果验证通过,不调用 e.preventDefault(),表单将正常以POST方式提交到LoginServlet
    });
</script>注意事项:
LoginServlet 中的 doPost 方法已经基本正确地处理了POST请求。以下是完善和强调其关键点的最佳实践:
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class LoginServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    // 建议在init方法中初始化数据库连接池或数据源,而不是在doPost中每次创建
    // public void init() throws ServletException { ... }
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 设置响应内容类型和字符编码,避免中文乱码
        response.setContentType("text/html;charset=UTF-8"); 
        PrintWriter out = response.getWriter();
        Connection con = null; // 声明在try块外,以便finally中关闭
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            // 1. 加载数据库驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            // 2. 建立数据库连接
            con = DriverManager.getConnection("jdbc:mysql://localhost:3306/student","root","root");
            // 3. 获取并转换请求参数
            String roomNoStr = request.getParameter("Roomno");
            String password = request.getParameter("password");
            // 参数空值检查(尽管前端已做,后端仍需再次验证,以防绕过前端)
            if (roomNoStr == null || roomNoStr.trim().isEmpty() || password == null || password.trim().isEmpty()) {
                out.println("房间号或密码不能为空。");
                return; // 提前返回
            }
            int roomNo;
            try {
                roomNo = Integer.parseInt(roomNoStr);
            } catch (NumberFormatException e) {
                out.println("房间号格式不正确,请输入数字。");
                e.printStackTrace();
                return; // 提前返回
            }
            // 4. 使用PreparedStatement防止SQL注入
            ps = con.prepareStatement("select roomNo, userName from login where roomNo=? and password=?");
            ps.setInt(1, roomNo);
            ps.setString(2, password);
            // 5. 执行查询
            rs = ps.executeQuery();
            // 6. 处理查询结果
            if(rs.next()) {
                // 登录成功
                int userRoom = rs.getInt("roomNo"); // 推荐使用列名获取
                String userName = rs.getString("userName"); // 推荐使用列名获取
                out.println("登录成功!房间号: " + userRoom + " 分配给 " + userName);
                // 实际应用中,登录成功后通常会进行重定向或转发到用户主页
                // request.getSession().setAttribute("loggedInUser", userName);
                // response.sendRedirect("welcome.jsp"); 
            } else {
                // 登录失败
                out.println("登录失败!房间号或密码不正确。");
            }
        } catch (ClassNotFoundException e) {
            out.println("数据库驱动加载失败,请检查配置。");
            e.printStackTrace();
        } catch (SQLException e) {
            out.println("数据库操作异常,请稍后再试。");
            e.printStackTrace();
        } finally {
            // 7. 关闭资源,避免资源泄露
            try {
                if (rs != null) rs.close();
                if (ps != null) ps.close();
                if (con != null) con.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            if (out != null) out.close(); // 确保PrintWriter关闭
        }
    }
}本文详细阐述了在Web应用中,如何正确地结合JavaScript客户端验证与Java Servlet后端处理来实现表单提交功能。核心要点在于:
遵循这些原则,开发者可以构建出既安全又用户友好的Web表单提交流程。
以上就是Web应用中JavaScript验证与Servlet表单提交的协同工作的详细内容,更多请关注php中文网其它相关文章!
 
                        
                        每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
 
                Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号