论技术官方似乎确比民间友好,strust之bean:include之感(一)
论技术官方似乎确比民间友好,jstl之c:import之感(二)
上篇文章“论技术官方似乎确比民间友好,struts之bean:include之感(一)”中分析了struts的bean:include的不足;
用c:import似乎是个比较完善的解决方案;
然而一物终降一物,工程应用的复杂,必然引出新的挑战,本文主要分析c:import的困惑
Exception
IllegalStateException: Cannot forward after response has
been committed
Exception情景
1)在Servlet1中用forward转向jsp1页面,然后JSP1的页面有一个链接,这个连接指向Servlet2,然后Servlet2再用forward转向jsp2
2)Action1
mapping.find("a.jsp")
a.jsp
<c:import url="b.do?method=doB&id=aid">
Reason
遇到Cannot
forward after response has been committed,是由于有页面显示后仍然含请求转向产生的,而当页面有输出之后是不能够重定向的,同理还适用于
repsonse.sendRedirect();
<jsp:forward page=""/>。
至于<c:import>造成的IllegalStateException:
Cannot forward after response has been committed原因
是因为某些时候Action的资料量太大,超出JSP默认的8kb,就会被迫使先把response传给使用者,这也就早晨管理其他资料没有办法完全传递过来,传递过来的时候响应已经做出了
Reference
Hans's Top Ten JSP Tips之Dealing with Buffer
Flushing Issues
An HTTP response message contains both headers and a body.
The headers tell the browser things like what type of data the body contains
(HTML text, an image), the size of the body, if the body can be cached, and so
on. Headers are also used to set cookies and to tell the browser to
automatically get another page (a redirect). All response headers must be sent
to the browser before the body is sent.
To allow parts of the
body to be produced
(from static template text as well as content generated dynamically by JSP
elements) before headers are set, the body is buffered. Instead of sending the response to the
browser as soon as something is written to the response body, the JSP container writes all
static markup code and all dynamic content
generated by JSP elements to the buffer.
At some point, such
as when the buffer is full or
the end of the page is reached, the container sends all headers that have been set
followed by the buffered body content. In servlet speak, this is called committing the response. After the response has been committed, you can't set headers, such
as for cookies or a redirection instruction. Another thing you can't do is forward the request to another
page.
In most cases, this is not a problem. The default buffer
size is 8KB, more than enough for a typical page, and you can increase it with
the buffer attribute of the page directive. But if you use the include action in a page, you may be
in for a surprise. Due to limitations in the way the servlet features
used by <jsp:include> are specified, the buffer is always flushed before the target
page is invoked. This means that you can't set headers or use <jsp:forward> after a <jsp:include> action.
An unfortunate side-effect of this automatic flushing is
that runtime errors triggered by JSP elements after a <jsp:include> action may not be
reported correctly, since many JSP containers use the forward mechanism to
display the error page. If you see an error message like "response already
committed" in a page with <jsp:include> elements, I suggest that you use the include
directive instead (at least until you have isolated the problem).
Hans's Top Ten JSP Tips之Choosing the Right
Include Mechanism
A JSP page can include page fragments from other files to
form the complete response. You can use this, for instance, to keep header,
footer, and navigation bar content in separate files and include them in all
other pages. There are two include mechanisms: the include directive and
the include action. It's not always obvious which one to use, though.
The include directive, <%@ include file="filename.inc" %>, includes the content
of the specified file during the translation phase--when the page is converted
to a servlet. The main page and the included file are simply merged. This means
that scripting variables declared in one file (using scripting elements or an
action element like <jsp:useBean>) are visible in all
files and must have unique names. Some containers detect changes in files
included with the directive, but the specification doesn't require it. Therefore,
changes you make to the included file in a running system may not be reflected
immediately; you may have to update the main JSP page, or remove the class file
generated for the main page in order to see the change.
The include action, <jsp:include page="pagename.jsp"
flush="true" />, includes the response generated by executing the
specified page (a JSP page or a servlet) during the request processing
phase--when the page is requested by a user. As opposed to the include
directive, the page name can be specified as a so-called request-time
attribute value, so which page to include can be decided when the main page
is requested. Since it's the response generated by the page that is included, not
the content of the page itself, scripting variables declared in one file are
not available to the other files. To share an object between the pages you must
instead place it in one of the following JSP scopes: request, session or
application scope. If you change a page included with the include action, the
change always takes effect immediately.
My rule of thumb for when to use the different mechanisms is
this:
o
Use
the include directive if the file changes rarely. It's the fastest
mechanism. If your container doesn't automatically detect changes, you can
force the changes to take effect by deleting the main page class file.
o
Use
the include action only for content that changes often, and if which
page to include cannot be decided until the main page is requested.
Solution
1) 加大jsp buff
How:<%@
page buffer="16kb" %>
Doubt: what would
be if the infos size larger than specified buffer? No problem, 8k is enough for one page
2) absolute path
Would make context imported part independence of the caller
context;就是说<c:import>引入的内容和当前整个页面的上下文并不完全一样。
3) 若为Servlet类
解决办法,在request.getRequestDispatcher("*.jsp").forward(request,
response);后加return;就OK拉
4)若URL里没有变量,用<%@ page=''%>即可