1

我正在使用 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的farward方法。但是在这里我在调用 forward 之前没有打印任何东西,因为我将所有数据传递给视图(bodyViewPath 变量),无论如何,我的 forward 方法在我的视图方法结束时被调用。

请帮我。

4

2 回答 2

2

我正在使用 JSP/Servlet 来构建网站。问题是,当我多次重新加载页面时抛出 IllegalStateException

那是因为您分配了HttpServletRequestHttpServletResponse作为应用程序范围的 servlet 实例的实例变量,这导致它们不是线程安全的。

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    // ...
    request = req; // Fail!
    response = resp; // Fail!
    // ...
}

如果您在短时间内触发多个请求,那么这些变量很有可能在它们仍在忙于处理时被完全不同的请求覆盖。

换句话说,您只是以错误的方式使用 servlet,并且您的整个 MVC 尝试也非常值得怀疑。首先了解 servlet 的工作原理,然后查找前端控制器模式 (但请仅将其用于学习/爱好目的,不要重新发明轮子)。

于 2011-12-18T01:59:21.720 回答
1

因此,鉴于此堆栈跟踪:

...
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

于 2011-12-17T21:26:23.487 回答