`

常见问题

 
阅读更多

1、Jsp标签中动态INCLUDE与静态INCLUDE的区别?

答:动态INCLUDE用jsp:include动作实现
<jsp:include page="included.jsp"/>它总是会检查所含文件中的变化,适合用于包含动态页面,并且可以带参数。


静态INCLUDE用include伪码实现(也即伪指令实现),不会检查所含文件的变化,适用于包含静态页面
<%@ include file="included.htm" %>


静态包含适用于不经常变动的文件,而动态包含适用于变化比较大的文件!

我们查看这些jsp->java代码:静态包含包含文件和被包含文件最后形成的是一个java代

文件。而动态包含最终形成的是两个java代码文件!

 

我们深入研究一下“使用了这两个标签的jsp文件对应的java代码段”:

假设 用b.jsp分别进行一次静态的和动态的包含c.jsp。

发现

对于静态包含(<%@ include file="c.jsp" %>):

out.write("<!-- c.jsp开始 --> ");

      out.print(request.getParameter("ano") );

      out.write('\r');

      out.write('\n');

      out.print(request.getParameter("bno") );

      out.write("\r\n");

out.write("<!-- c.jsp结束 -->");

对于动态包含(<jsp:include page="included.jsp"/>)的代码片段:

if (true) {

        _jspx_page_context.forward("c.jsp");

        return;

}

说明静态包含是把c.jsp文件先翻译为java代码,然后把这些java代码加入到

b.jsp翻译后的java代码中,位置不变(在jsp中的位置和翻译为java代码后的位置)

这里需要指出的是c.jsp中不能使用<html>、</html>、<body>、</body>标记,因为这将会影响在原JSP文件中同样的标记,有时会导致错误,如果去掉了这些标记还出错,那么你要检测被包含文件和包含文件中使用的<%%>是否有相同的变量或方法!为什么?我们之前说过这个标签内部的代码都要放到jsp_service方法中,这两个文件如果有相同的变量,在使用静态包含后,就相当于你在这个标签中进行了两次相同变量的声明!

对于动态包含,我们发现它其实它是服务器端跳转!

 

2、Jsp标签两种跳转方式分别是什么?有什么区别?

答:有两种,分别为:
<jsp:include page="included.jsp" flush="true">
<jsp:forward page= "nextpage.jsp"/>
前者页面不会转向include所指的页面,只是显示该页的结果,主页面还是原来的页面。执行完后还会回来,相当于函数调用。并且可以带参数.

后者完全转向新页面,不会再回来。相当于go to 语句。  

 

您可能已注意到 jsp:include 代码示例中的 flush 属性。顾名思义, flush 指示在读入包含内容之前是否清空任何现有的缓冲区。JSP 1.1 中需要 flush 属性“=true”,因此,如果代码中不用它,会得到一个错误。但是,在 JSP 1.2 中, flush 属性缺省为 false。由于清空大多数时候不是一个重要的问题,因此,我的建议是:对于 JSP 1.1,将 flush 设置为 true;而对于 JSP 1.2 及更高版本,将其设置为关闭。

清空现有缓冲区,是清空那里?tomcat目录下的work目录就是所谓的缓冲区!

 

个人理解,仅存在两种跳转(跳转):“服务器转向”和“客户端转向”。

假设:在视图a进行表单提交,请求url-A,url-A在服务端请求向url-B,….,url-N,

服务器器转向的特点:地址栏不变,请求信息不丢失;而客户端跳转却恰恰相反,它仅仅是向客户端发送一个状态码和地址(这个地址可以携带参数),让客户端那这个地址去重新访问服务器端。

以上述“假设”为基础,说这些url之间的转向是服务器转向,意思是说他们之间的跳转发生在服务器端,它给客户一个错觉让客户感觉到它访问的是url-A,其实不是,它访问的是url-N,但客户不知道!根据上面的“假设”我们并不能判断出视图a到url-N之间他们究竟进行的是什么跳转!这要看这种跳转是由谁引导的,

 

服务器跳转发生在下列两种情况下:

*  <jsp:forward page=””/>

* request.getRequestDispatcher("url").forward(request, response);

 

而客户端跳转发生在下列几种情况

* 表单提交

* 超链接

* response.sendRedirect("url?参数");

 

 

3、JspWriter和PrintWriter

 

JspWriter是jsp 9大内置对象之一,是javaEE范畴,在servlet中只能通过PageContext内置对象获得,而PageContext只能通过JspFactory获得。而且JspWriter是一个继承自j2se抽象类Writer的抽象类。

PrintWriter属于j2se范畴,继承自j2se抽象类Writer的类,而且PrintWriter不是抽象类。而且在servlet中可以通过response获得。

JspWriter和PrintWriter这两个类的方法在没有牵扯到缓冲的时候方法可以通用。所以我们在servlet类中经常使用PrintWriter类。

 

 

4、<%%>和<!%%>

<%%>与<!%%>的区别,后者声明全局变量,后者可以声明方法,前者不能声明方法,其他都相同!可以这样说,前者在jsp翻译为servlet后位于一个方法内(_jspService方法),后者将成为servlet类的一个字段或者该类的一个方法!

 

 

5、异常

异常名字:java.lang.IllegalStateException: getOutputStream() has already been called for this response   

 在jsp或者在servlet中有时要用到response.getOutputStream(),但是此时会在后台报这个错误java.lang.IllegalStateException: getOutputStream() has already been called for this respons,这问题困扰了我好久都没解决,最近这个项目中我又遇到了,下定决心一定要解决掉,最后终于让我给找到解决的方法了,这个异常时因为response.getOutputStream()跟response.getWriter()相冲突早场的,呵呵!现在记录下,发出来和大家共享下,希望能帮到遇到同样问题的朋友们,解决方法如下:

    out.clearBuffer(); 

    out = pageContext.pushBody();

在调用response.getOutputStream()之前加上上面两代码,就ok了!

为什么?

JSP的主要功能是描述发送到客户请求的响应输出流中的数据。这个输出流通过out对象显露给JSP开发员。

Out对象是javax.servlet.jsp.JspWriter对象的实例。这个对象可以代表输出流、经过滤的输出流或来自其他JSP页面的嵌套的JspWriter对象。但是输出应该不会被直接发送到输出流,因为在JSP的生命期内可能有多个输出流。

根据页面是否被缓冲,初始的JspWriter对象的初始化有所不同。缺省情况下,每个JSP页面都打开了缓冲,这可以提高性能。缓冲功能很容易关闭,只要使用page指令的buffered='false'属性即可。

缓冲的out对象以块为单位收集和发送数据,这通常会提供最好的总体吞吐量。使用缓冲时,PrintWriter在第一个块被发送时创建,也就是在out第一次调用flush()时。

如果不缓冲输出,将立即创建PrintWriter对象并引用out对象。在此情况下,发送到out对象的数据立即被发送到输出流。创建PrintWriter对象时将使用由服务器决定的缺省设置和头信息。

 

注意:HTTP头和缓冲

HTTP使用响应头描述服务器以及定义发往客户的数据的某些方面信息。这可能包括页面的MIME内容类型、新的cookie、转发URL或其他HTTP“动作”。

JSP允许开发者在创建OutputStream(即PrintWriter)前改变响应头的内容。一旦建立了OutputStream,头信息就不能改变了,因为它已被发送到客户。

在缓冲的out对象的情况下,直至缓冲区第一次刷新时才建立OutputStream。缓冲区被刷出很大程度上取决于page指令的autoFlush和bufferSize属性。通常,最好在有任何数据被发送到out对象前设置头信息。

对无缓冲的out对象,很难设置页面头。当无缓冲的页面建立时,几乎立即就建立了OutputStream。

在建立OutputStream后发送的头可能会造成大量不正常的结果。一些头被简单地忽略,其他的头可能产生异常,例如IllegalStateException。

 

JspWriter包含的方法大多数与java.io.PrintWriter类一样。但是JspWriter有另外几个用于处理缓冲的方法。与PrintWriter对象不同,JspWriter抛出IOExceptions。在JSP中,这些异常需要显式捕获和处理。

 

注意:autoFlush( )

在JSP中,缺省的缓冲行为是在缓冲区满了时自动刷出缓冲区。但是,有时JSP实际上是直接和另一个应用程序通信。在此情况下,不“何时”的行为可能是在超出缓冲区时抛出异常。

设置page指令的属性autoFlush='false'将造成缓冲区溢出而抛出异常。

 

 

 

5、pageEncodingcontentType

pageEncoding的charset是jsp文件本身的编码

contentType的charset是指服务器发送给客户端时的内容编码

JSP要经过两次的“编码”,第一阶段会用pageEncoding,第二阶段会用utf-8至utf-8,第三阶段就是由Tomcat出来的网页, 用的是contentType。

第一阶段是jsp编译成.java,它会根据pageEncoding的设定读取jsp,结果是由指定的编码方案翻译成统一的UTF-8 JAVA源码(即.java),如果pageEncoding设定错了,或没有设定,出来的可能就是中文乱码。

第二阶段是由JAVAC的JAVA源码至java byteCode的编译,不论JSP编写时候用的是什么编码方案,经过这个阶段的结果全部是UTF-8的encoding的java源码。

JAVAC用UTF-8的encoding读取java源码,编译成UTF-8 encoding的二进制码(即.class),这是JVM对常数字串在二进制码(java encoding)内表达的规范。

第三阶段是Tomcat(或其的application container)载入和执行阶段二的来的JAVA二进制码,输出的结果,也就是在客户端见到的,这时隐藏在阶段一和阶段二的参数 contentType就发挥了功效

contentType的设定.

pageEncoding 和contentType的预设都是 ISO8859-1. 而随便设定了其中一个, 另一个就跟着一样了(TOMCAT4.1.27是如此). 但这不是绝对的, 这要看各自JSPC的处理方式. 而pageEncoding不等于contentType, 更有利亚洲区的文字 CJKV系JSP网页的开发和展示, (例pageEncoding=GB2312 不等于 contentType=utf-8)。

jsp文件不像.java,.java 在被编译器读入的时候默认采用的是操作系统所设定的locale所对应的编码,比如中国大陆就是GBK,台湾就是BIG5或者MS950。而一般我们不管 是在记事本还是在ue中写代码,如果没有经过特别转码的话,写出来的都是本地编码格式的内容。所以编译器采用的方法刚好可以让虚拟机得到正确的资料。

但是jsp文件不是这样,它没有这个默认转码过程,但是指定了pageEncoding就可以实现正确转码了。

举个例子:

<%@ page contentType="text/html;charset=utf-8" %>

大都会打印出乱码,因为输入的“你好”是gbk的,但是服务器是否正确抓到“你好”不得而知。

但是如果更改为

<%@ page contentType="text/html;charset=utf-8" pageEncoding="GBK"%> 

这样就服务器一定会是正确抓到“你好”了。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics