我正在使用JSP / Servlet来构建网站。问题是,当我多次重新加载页面时,会抛出IllegalStateException或者在页面中出现相同的数据变量(为什么,还没有javascript?)。
这是调用实现的视图方法的Page.class。
public abstract class Page extends Action {
protected String bodyViewPath = "body.jsp";
protected String layoutPath = "index.jsp";
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// TODO Auto-generated method stub
request = req;
response = resp;
try{
view();
}catch(Exception e) {
throw new RuntimeException(e);
}
}
protected void forward() throws Exception {
String base = "/WEB-INF/";
request.setAttribute("bodyViewPath", base +"/views/" + bodyViewPath);
request.getRequestDispatcher(base + layoutPath).include(request, response);
}}
AdminPage.class:
public class AdminPage extends Page {
protected List<String> parameters;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
try{
request = req;
response = resp;
if(getSession().getAttribute("user") == null) {
redirect("/admin/login");
return;
}
parseParameters();
if(parameters.size() == 0) {
redirect("/admin/index");
return;
}
getTargetInstance().doGet(request, response);
}catch(Exception e) {
throw new RuntimeException(e);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
try{
request = req;
response = resp;
parseParameters();
if(getSession().getAttribute("user") == null) {
redirect("/admin/login");
return;
}
if(parameters.size() == 0) {
throw new RuntimeException("Not allowed");
}
getTargetInstance().doPost(request, response);
}catch(Exception e) {
throw new RuntimeException(e);
}
}
protected void parseParameters() {
String requestURI = request.getRequestURI().substring(1);
parameters = new ArrayList<String>();
List<String> params = Arrays.asList(requestURI.split("/"));
if(params.size() > 2) {
for(int i = 2; i < params.size(); i++) {
parameters.add(params.get(i));
}
}
}
protected Action getTargetInstance() throws Exception {
String actionName = parameters.get(0).substring(0,1).toUpperCase() + parameters.get(0).substring(1).toLowerCase();
Class<Action> clazz = (Class<Action>) Class.forName("servlet.admin." + actionName);
return clazz.newInstance();
}
}
这是扩展Page.class的主要索引页面,我用它来查看注册用户列表。
package servlet.admin;
import java.util.List;
import core.Page;
import data.Users;
public class Index extends Page {
public Index() {
bodyViewPath = "admin/index.jsp";
}
public void view() throws Exception {
List<Users> users = (List<Users>) pm.newQuery(Users.class).execute();
setRequestAttribute("users", users);
setRequestAttribute("logout_url", request.getContextPath() + "/admin/logout");
forward();
}}
这是布局:
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<jsp:include page="${bodyViewPath}" />
</body>
</html>
这是视图文件:
<%@include file="/WEB-INF/includes.jsp" %>
<h1>List of registered users</h1>
<div>
<a href="${logout_url}">Logout</a>
</div>
<table>
<tr>
<th>ID</th>
<th>Name</th>
<th>Surname</th>
</tr>
<c:forEach items="${users}" var="user">
<tr>
<td>${user.id}</td>
<td>${user.name}</td>
<td>${user.surname}</td>
</tr>
</c:forEach>
</table>
例外:
HTTP Status 500 -
type Exception report
message
description The server encountered an internal error () that prevented it from fulfilling this request.
exception
java.lang.RuntimeException: java.lang.RuntimeException: java.lang.IllegalStateException: Cannot forward after response has been committed
core.AdminPage.doGet(AdminPage.java:38)
javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
root cause
java.lang.RuntimeException: java.lang.IllegalStateException: Cannot forward after response has been committed
core.Page.doGet(Page.java:23)
core.AdminPage.doGet(AdminPage.java:36)
javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
root cause
java.lang.IllegalStateException: Cannot forward after response has been committed
core.Page.forward(Page.java:43)
servlet.admin.Index.view(Index.java:17)
core.Page.doGet(Page.java:21)
core.AdminPage.doGet(AdminPage.java:36)
javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
note The full stack trace of the root cause is available in the Apache Tomcat/7.0.5 logs.
在询问我何时搜索之前,很多人都说这是因为RequestDispatcher的远程方法。但是我在调用前没有打印任何东西,因为我将所有数据传递给视图(bodyViewPath变量),无论如何,我的视图方法结束时调用了我的forward方法。
请帮助我。
答案 0 :(得分:2)
我正在使用JSP / Servlet来构建网站。问题是,当我多次重新加载页面时抛出IllegalStateException
那是因为您将HttpServletRequest
和HttpServletResponse
指定为应用程序范围的servlet实例的实例变量,导致它们不是线程安全。
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// ...
request = req; // Fail!
response = resp; // Fail!
// ...
}
如果你在短时间内发出多个请求,那么这些变量在他们仍在忙着处理时被完全不同的请求覆盖的可能性很大。
换句话说,你只是以错误的方式使用servlet,而你的整个MVC尝试也是非常值得怀疑的。 First learn how servlets works然后lookup the front controller pattern(但请将其用于学习/爱好目的,不要重新发明轮子)。
答案 1 :(得分:1)
所以,给定这个stacktrace:
...
core.Page.doGet(Page.java:21)
core.AdminPage.doGet(AdminPage.java:36)
...
以及HttpServletResponse
中Page.doGet
已提交且AdminPage.doGet
中未提交的事实必定存在问题代码行:
request = req;
response = resp;
if(getSession().getAttribute("user") == null) {
redirect("/admin/login");
return;
}
parseParameters();
if(parameters.size() == 0) {
redirect("/admin/index");
return;
}
getTargetInstance().doGet(request, response);
您需要通过粗略的System.outing或调试代码来调查response
变为committed
的确切位置。