这两天在细看<深入体验Java_Web开发内幕-核心基础>一书,书比较老了,使用的tomcat和servlet版本差距都比较大。书中提及在foward转发过程中,request对象和response对象一直都是同一个。但我总觉得有些问题,做了以下测试:
@WebServlet("/Test")
public class ForwardingServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("访问req:"+req.hashCode());
System.out.println("访问resp:"+resp.hashCode());
req.setAttribute("req",req);
req.setAttribute("resp",resp);
req.getRequestDispatcher("Input").include(req,resp);
}
}
@WebServlet("/Input")
public class ForwardedServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("转到req:"+req.hashCode());
System.out.println("转到resp:"+resp.hashCode());
if(req.getAttribute("req")==req)System.out.println("req:"+true);
else System.out.println("req:"+false);
if(req.getAttribute("resp")==resp)System.out.println("resp:"+true);
else System.out.println("resp:"+false);
}
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%
System.out.println("Jspreq:"+request.hashCode());
System.out.println("JSPresp:"+response.hashCode());
if(request.getAttribute("req")==request)System.out.println("req:"+true);
else System.out.println("req:"+false);
if(request.getAttribute("resp")==response)System.out.println("resp:"+true);
else System.out.println("resp:"+false);
%>
</body>
</html>
FowardingServlet分别转向jsp和servlet的输出结果如下:
从结果可以发现,foward方法resp的对象是同一个,req的对象不是同一个,include方法四个对象都不一样。
因此,关于缺省servlet的一些疑点就可以解释清楚了,一个response对象只能使用字节流或者字符流中的一个,当访问一个静态HTML文件,图片等资源时,是通过缺省servlet去访问的,因此如果在访问servlet里面转到一个图片,又调用了getWriter输出了数据,则会报错,这是因为它们共享一个servlet,而且读取图片只能用字节流。在转发的前后其实都不应该调用输出流,因为如果在调用foward之前如果又数据被输出到了客户端,则会报异常,如果没有,则缓冲区会被清空,并且foward之后的写入操作会被忽略。对于include与书中出入有点大,因为4个对象都不一样,你干你的,我做我的,互不干扰,因此不论转发到的文件是采用什么流写入的数据,与原servlet没有关系,只要不再一个servlet中同时使用字节流和字符流就行。