doPost方法无法获取请求属性,出现NullPointerException问题排查
问题分析与解决方案
兄弟,我一眼就看出问题所在了——HTTP是无状态协议,你遇到的NullPointerException本质是因为doGet和doPost是两次完全独立的HTTP请求,它们对应的HttpServletRequest对象完全不一样,所以你在doGet里设置的request属性,到doPost请求时早就不存在了!
为什么会出现这个问题?
request.setAttribute()存储的属性,生命周期只限于当前请求:你在doGet里把foo存到request里,只能在这次GET请求的转发/包含过程中使用(比如你forward到updatefoo.jsp时能拿到),但当用户在jsp里提交表单触发POST请求时,这已经是一个全新的request对象,之前的属性自然就丢失了。- 你说存session也无效?大概率是你存session的方式有问题,或者会话被意外销毁了(比如浏览器重启、会话超时),正常情况下session是跨请求保留的。
两种可行的解决方案
方案一:用Session跨请求存储Foo对象(适合需要保留完整对象的场景)
修改doGet方法,把foo存到session中,而不是request:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { int id = Integer.parseInt(request.getParameter("id")); Foo foo = fooDao.getFooById(id); System.out.println(foo.toString()); // 将foo存入session,跨请求保留 request.getSession().setAttribute("foo", foo); // 建议用forward而不是include,更符合页面跳转的逻辑 RequestDispatcher dispatcher = request.getRequestDispatcher("updatefoo.jsp"); dispatcher.forward(request, response); } catch (NumberFormatException e) { // 处理ID格式错误的情况,比如跳回列表页 response.sendRedirect("fooList.jsp"); } }
然后在doPost方法中从session获取,用完记得移除避免内存占用:
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpSession session = request.getSession(false); // 不自动创建新session if (session != null) { Foo notUpdatedFoo = (Foo) session.getAttribute("foo"); if (notUpdatedFoo != null) { System.out.println(notUpdatedFoo.toString()); // 这里可以获取表单提交的新数据,更新foo对象后调用DAO保存 // fooDao.updateFoo(notUpdatedFoo); // 用完立即移除session中的foo,避免内存泄漏 session.removeAttribute("foo"); // 跳转到成功页面或列表页 response.sendRedirect("fooList.jsp"); } else { // 处理foo不存在的情况 response.sendRedirect("fooList.jsp"); } } else { // 会话失效,比如用户未登录,跳转到登录页 response.sendRedirect("login.jsp"); } }
方案二:在表单中传递Foo的ID(轻量无状态方案,更推荐)
既然最终你需要的是Foo的ID来更新,其实可以不用存对象,直接在updatefoo.jsp的表单里加一个隐藏域传递ID,然后在doPost中重新从数据库查询Foo:
<form action="UpdateFooServlet" method="post"> <!-- 你的其他表单字段,比如foo的名称、描述等 --> <input type="hidden" name="fooId" value="${foo.id}"> <button type="submit">更新Foo</button> </form>
修改doPost方法,通过ID重新查询Foo:
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { int fooId = Integer.parseInt(request.getParameter("fooId")); Foo notUpdatedFoo = fooDao.getFooById(fooId); if (notUpdatedFoo != null) { System.out.println(notUpdatedFoo.toString()); // 获取表单提交的新数据,更新foo对象 // notUpdatedFoo.setName(request.getParameter("name")); // fooDao.updateFoo(notUpdatedFoo); response.sendRedirect("fooList.jsp"); } else { response.sendRedirect("fooList.jsp"); } } catch (NumberFormatException e) { response.sendRedirect("fooList.jsp"); } }
额外注意事项
- 尽量避免用
include跳转页面,forward更符合页面跳转的业务逻辑; - 处理
Integer.parseInt()时一定要加异常捕获,防止用户传递非法ID导致程序崩溃; - 用session存储对象时,务必在使用后移除,避免会话内存占用过高。
内容的提问来源于stack exchange,提问作者jimmyrap
相关产品推荐
相关产品推荐

