jsp与servlet是一体的两面,jsp最后都会被容器转译为servlet源代码,自动编译为.class文件,载入.class文件然后生成servlet对象。
由容器转译后的servlet类具有_jspinit()、_jspdestroy()、_jspservice()等方法,名称中有下划线前缀,表示这些方法都是容器转译时维护的,我们不应该从写这些方法。如果想要做些jsp初始化或收尾的工作,则应定义jspinit()或jspdestryoy()方法。
jsp指示(directive)元素的主要目的在于,指示容器将jsp转译为servlet源代码时,必须遵守的一些信息。指示元素的语法如下:
在jsp中有三种常用的指示类型:page、include和taglib。
page指示类型告知容器如何转译当前的jsp网页。
include指示类型告知容器将别的jsp页面包括进来进行转译。
taglib指示类型告知容器如何转译这个页面中的标签库(tag library)。
指示元素中可以有多对属性/值,必要时,同一个指示类型可以用数个指示元素来设置。
page指示类型中的import告知容器,转译jsp时必须在源代码中包括的import语句。也可以在一个import语句中,使用逗号分隔开数个import的内容;page指示类型中的contenttype属性告知容器,在转译jsp时,必须使用httpservletrequest的setcontenttype(),调用方法时传入的参数就是contenttype的属性值;pageencoding属性则是告知容器转译和编译时如何处理这个jsp网页中的文字编码,以及内容类型附加的charset设置。如果网页中包含非ascii编码范围内的字符(如中文),就要指定正确的编码格式,才不会出现乱码。
可以在使用page指示类型时一行一行的编写,也可以编写在同一个元素中。
page指示类型还有一些可以设置的属性,概略说明如下:
info属性
用于设置当前jsp页面的基本信息,这个信息最后会转换为servlet成u型中使用getservletinfo()所取得的信息。
autoflush属性
用于设置输出流时候要自动清除,默认为true。如果设置为false,当缓冲区满了又没调用flush()把数据送出到客户端时,就会产生异常。
buffer属性
用于设置到客户端的输出串流缓冲区的大小,设置时必须指定单位,流入buffer=”16kb”,默认是8kb。
errorpage属性
用来设置当jsp运行错误而产生异常时,该转发哪一个页面处理这个异常。
extends属性
用来指定jsp网页转译为servlet程序之后,应该继承哪一个类。以tomcat为例,默认是继承至httpjspbase(它继承至httpservlet)。这个属性很少会使用到。
iserrorpage属性
设置jsp页面是否为处理异常的页面,这个属性要与errorpage配合使用。
language属性
指定容器使用哪种语言的语法来转译jsp网页,不过事实上目前只能使用java的语法且是默认的。
session属性
设置在转译后的servlet源代码中是否具有创建httpsession对象的语句。默认是true,若有些页面不需作会话管理,设为false可以增加一些性能。
iselignored
设置jsp网页中是否忽略表达式语言,默认是false。这个设置会覆盖web.xml中的<code><el-ignored></code>设置。
isthreadsafe属性
告诉容器在编写jsp时是否注意到线程安全,默认值为true。如果设置为false,则转译之后的servlet会实现singlethreadmodel接口,每次请求时将创建一个servlet实例来服务请求,虽然可以避免线程安全问题,但这会影响到性能,极度不建议设置为false。
incude指示类型用来告知容器将包括另一个网页的内容进行转译。
使用命令元素include来包括其他网页内容时,由于是在转译时期就决定了转译后的servlet内容,是一种静态的包含方式。<code><jsp:include></code>标签则是在运行时将别的网页动态包括进来进行响应的方式。
jsp网页会转译为servlet类,转译后的servlet类应该包括哪些类成员、方法声明或是哪些语句,在编写jsp时,可以使用声明(declaration)元素、scriptlet元素以及表达式(expression)元素来指定。
声明元素的语法如下:
在<code><%!</code>与<code>%></code>之间声明的程序代码,都将转译为servlet中的类成员或方法。
在使用<code><%!</code>与<code>%></code>声明变量时,必须小心数据共享与线程安全的问题。容器默认会使用同一个servlet实例来服务不同用户的请求,每个请求就是一个线程,而<code><%!</code>与<code>%></code>之间声明的变量对应至类变量成员,因此会有线程共享访问的问题。
如果有一些初始化操作想要在jsp加载时执行,则可以重写jspinit()方法,也可以用jspdestroy()定义结尾动作。定义这两个方法就是在<code><%!</code>与<code>%></code>之间进行的,这样转译后的servlet源代码就会有相对应的片段出现。
scriptlet元素语法如下:
在scriptlet元素中可以编写java语句,就如同在java的方法中编写语句一样,事实上,其中所包括的内容将被转译为servlet源代码的_jspservice()方法中的内容。
直接在jsp中编写的html,都会变成out对象所输出的内容。scriptlet出现的顺序,也就是在转译为servlet后,语句出现在_jspservice()中的顺序。
表达式元素语法如下:
表达式运算的结果将直接输出为网页的一部分。在表达式元素中不用加上分好(;)。
隐含对象
说明(转译后对象的对象)
out
jspwriter–>printwriter
request
httpservletrequest
resposne
httpservletresponse
config
servletconfig
application
servletcontext
session
httpsession
pagecontext
pagecontext,它提供了jsp页面资源的封装
exception
throwable,它代表jsp页面抛出的异常对象
page
this
可以通过pagecontext设置四种范围属性,而不用使用个别的pagecontext、request、session、application来进行设置。以pagecontext提供单一的api来关系属性的作用范围,可以使用以下的方法来进行设置。
scope可以使用以下常数来指定:
pagecontext.page_scope
pagecontext.request_scope
pagecontext.session_scope
pagecontext.application_scope
事实上,很少会使用到pagecontext,pagecontext主要是在转译jsp为servlet时,提供给容器一个单一访问的界面。
jsp终究会转译为servlet,所以错误可能发生在以下三个时候:
jsp转换为servlet源代码时
语法错误等
servlet源代码进行编译时
忘记部署相关的类等
servlet加载容器进行服务单发生运行时错误
如nullpointerexception等