Servlet无法转发至JSP求助:表单验证中Line-A执行报错
解决表单验证中请求转发报错的问题
嘿,我看了你的代码和遇到的问题——Line-A执行时跳转报错,但Line-B和Line-C正常,核心问题出在Hibernate事务与会话的生命周期管理,还有一些逻辑流程的疏漏,咱们一步步来修复:
1. 先揪出导致Line-A报错的直接原因
你在Line-A执行include的时候,Hibernate的事务还没提交,会话s1也还处于活跃状态。在事务未结束的情况下执行请求包含操作,会导致数据库会话和请求处理线程产生资源冲突,这就是Line-A报错的主要原因。
同时,你的代码还有几个隐藏问题:
- 当用户不存在(
u2 == null)时,s1的会话和事务根本没关闭,会造成资源泄漏 - 每次请求都创建新的
SessionFactory,这是重量级对象,频繁创建会耗尽服务器资源 - 注册逻辑的位置不对,不管用户是否存在都会执行注册,逻辑混乱
2. 分步修复方案
(1)规范事务与会话的生命周期
事务的提交、会话的关闭必须放在数据库操作完成之后,页面跳转之前。而且要确保无论逻辑分支如何,会话都能被关闭,避免资源泄漏。
(2)修正用户验证的逻辑流程
把注册逻辑放到“用户不存在”的分支里,这样才符合正常的“先验证,不存在再注册”的流程,避免重复执行不必要的代码。
(3)单例化SessionFactory
SessionFactory应该全局初始化一次,而不是每次请求都创建。可以在Servlet的init()方法中初始化,destroy()方法中销毁。
3. 修正后的完整代码
import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; @WebServlet("/client") public class ClientServlet extends HttpServlet { private static final long serialVersionUID = 1L; // 全局单例SessionFactory private SessionFactory sessionFactory; @Override public void init() throws ServletException { super.init(); // 仅初始化一次SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory(); } public ClientServlet() { super(); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 直接访问POST接口时重定向到登录页 response.sendRedirect("Clientlog.jsp"); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String username = request.getParameter("username"); String password = request.getParameter("password"); Session session = null; Transaction transaction = null; try { session = sessionFactory.openSession(); transaction = session.beginTransaction(); // 查询用户是否存在 Query q = session.createQuery("from userdb where username = ?"); q.setString(0, username); userdb u2 = (userdb) q.uniqueResult(); if (u2 != null) { // 用户存在,验证密码 if (u2.getPassword().equals(password)) { // 验证成功,跳转首页 request.getRequestDispatcher("home.jsp").forward(request, response); } else { // 密码错误,返回登录页并提示 request.setAttribute("error", "Invalid username/password, please try again"); request.getRequestDispatcher("Clientlog.jsp").forward(request, response); } } else { // 用户不存在,创建新用户 userdb u1 = new userdb(); u1.setUsername(username); u1.setPassword(password); session.save(u1); // 注册成功跳转首页 request.getRequestDispatcher("home.jsp").forward(request, response); } // 提交事务 transaction.commit(); } catch (Exception e) { // 异常时回滚事务 if (transaction != null) { transaction.rollback(); } // 把异常信息传递到页面 request.setAttribute("error", "An error occurred: " + e.getMessage()); request.getRequestDispatcher("Clientlog.jsp").forward(request, response); e.printStackTrace(); } finally { // 确保会话一定会被关闭 if (session != null && session.isOpen()) { session.close(); } } } @Override public void destroy() { super.destroy(); // 销毁Servlet时关闭SessionFactory if (sessionFactory != null && !sessionFactory.isClosed()) { sessionFactory.close(); } } }
额外优化说明
- 把类名改成
ClientServlet,符合Java大驼峰的命名规范 - 用
forward替代include,因为登录/注册后的跳转更适合用完全转发,避免保留原Servlet的响应状态 - 添加了完整的异常处理,确保出现错误时事务能回滚,资源能释放,还能给用户提示
doGet方法添加了重定向,避免用户直接访问POST接口时出现空白页面
内容的提问来源于stack exchange,提问作者user8885515
相关产品推荐
相关产品推荐

