JSP学习笔记(一)
概述
JSP是基于Java语言的动态网页技术,它以“.jsp”为扩展名。在一个JSP页面中可以包括指令标识、HTML代码、JavaScript代码、嵌入的Java代码、注释和JSP动作标识等内容,但这些内容并不是一个JSP页面所必须的。当JSP文件部署到Web应用服务器中后并不能直接回应给浏览器,其运行需要经历4个关键阶段,如图所示。
当浏览器向Web应用服务器请求一个JSP页面时,Web应用服务器将其转换为一个Servlet文件(即一个.java文件),然后将这个Java文件编译为一个字节码文件(即一个.class文件)。最后Web应用服务器加载转换后的Servlet实例,处理客户端的请求,并返回HTML格式的响应回应给客户端浏览器。
JSP指令标识
指令标识主要用于设置整个JSP页面范围内有效的相关信息,这些标识会被服务器解释执行,但不会产生任何内容输出到网页中。JSP中包含了page、include和taglib共3个指令标识,其语法结构相同,定义的方法如下:
1 | <%@ 指令名 属性1="属性值1" 属性2="属性值2" ...... %> |
(1)指令名:指定指令名,取值为page、include和taglib指令。
(2)属性:指定属性名称,不同的指令包含不同的属性。如果在一个指令中需要设置多个属性,则属性之间用逗号或空格分隔。
(3)属性值:指定属性值。
页面指令page
页面指令page是JSP页面中最常用的指令,也是每一个JSP页面中必须要用到的一个指令。其作用是定义与整个JSP页面相关的属性,比如JSP页面的编码、内容类型及引用的类库等,当这些属性被服务器解析成Servlet时会转换为相应的Java程序代码。page指令的语法格式如下:
1 | <%@ page属性1="属性值1" 属性2="属性值2" ...... %> |
(1)page:声明指令为page指令。
(2)属性:指定page指令中的属性名。
(3)属性值:指定属性值。
在使用一个指令时注意指令名与@符号之间有一个空格。
page指令提供了如下属性,在实际编程过程中其中的很多属性可以省略,该指令会使用默认值来设置JSP页面。
(1)language属性:指定当前页面中使用的语言,目前只支持Java语言,以后可能会支持其他语言。该属性的默认值为Java。
(2)contentType属性:设置JSP页面的MIME类型和字符编码,浏览器会根据该属性指定的类型和编码显示网页内容。
(3)pageEncoding属性:设置JSP页面的编码格式,在JSP页面中所有代码都使用该属性指定的字符集。如果设置为ISO-8859-1,则该JSP页面不支持中文字符。通常情况下,需要将其设置成为支持中文的字符集。
(4)import属性:导入JSP页面中的类包,导入后在JSP页面中可以通过嵌入Java代码的方法使用这些类包。
(5)buffer属性:设置out对象使用的缓冲区大小,默认为8 KB。其单位只能使用KB。建议开发人员使用8的倍数(如16、32、64和128等)作为该属性的属性值。
(6)autoFlush属性:指定当缓冲区已满时自动将缓冲区中的内容输出到客户端,默认值为true。如果设置为false,当缓冲区已满时将抛出JSP Buffer overflow异常。
如果将buffer属性的值设置为none,则autoFlush属性不能设置为false。
(7)isErrorPage属性:将当前JSP页面设置为错误处理页面,以处理另一个JSP页面的错误,即异常处理。只有在错误处理页面中将isErrorPage属性设置为true时,才可以调用exception对象输出错误信息。
(8)errorPage属性:指定当前页面出现异常时调用的另一个页面(即错误处理页面),在错误处理页面中必须将isErrorPage属性值设置为true。
例如,指定当前页面出现异常时调用error.jsp页面显示错误信息的代码如下:
1 | <%@ page errorPage="error.jsp" %> |
在error.jsp页面需要通过以下面的代码将该页面设置为错误处理页面:
1 | <%@ page isErrorPage="true" %> |
然后在error.jsp页面中即可通过以下代码输出错误提示信息:
1 | <%=exception.getMessage()%> |
(9)session属性:指定当前JSP页面是否支持session,默认值为true,即支持session。
(10)isELIgnored属性:指定是否禁用EL表达式,如果为true,该页面将忽略EL表达式;否则将执行EL表达式。
(11)isThreadSafe属性:指定JSP页面是否是线程安全的,如果为true,则表明JSP页面在同一时间可以被多个线程访问;否则不可。
文件包含指令include
include指令是JSP提供的页面包含指令,它可以将一个JSP页面包含到另一个JSP页面中实现JSP页面的重用,包含文件的过程如图所示。
include指令是静态包含,即被包含文件中所有内容会被原样包含到该JSP页面中。即使被包含文件中有JSP代码,在包含时也不会被编译执行。将两个页面组合成一个页面后编译处理,最后返回结果页面。
使用include指令最终将生成一个文件,所以在被包含和包含的文件中不能有相同名称的变量;否则会发生编译错误。
include指令的语法格式如下:
1 | <%@ include file="path" %> |
该指令只有一个file属性,用于指定要包含文件的路径,该路径可以是相对或绝对路径。
通常情况下,一个网站之中的页面头部(banner部分)与底部(版权信息部分)都是相同的,可以分别创建这两个页面。然后通过include指令将其包含在其他页面中,从而减少冗余代码。
引用标签库指令taglib
taglib指令用于声明一个标签的引用,在JSP页面之中声明了哪个标签库的引用,即可在JSP页面中调用哪个标签。该指令的语法格式如下:
1 | <%@ taglib prefix="tagPrefix" uri="tagURI" %> |
(1)taglib属性:声明指令为taglib指令。
(2)prefix属性:指定标签库的前缀。
(3)uri属性:指定标签库文件的位置。
在JSP页面中使用标签库可以简化JSP页面并减少Java代码,目前使用十分广泛,如常用的标签库有JSTL、Sturs标签和Spring标签等。
使用JSP脚本
JSP之所以应用灵活,其主要原因是在JSP页面中可以很方便地调用Java或脚本代码来实现所需功能。JSP中的脚本标识包括JSP表达式(Expression)、声明标识(Declaration)和脚本程序(Scriptlet)。通过这些标识,在JSP页面中可以如编写Java程序一样来声明变量、定义方法或执行各种表达式的运算。
在JSP中应用代码片段
代码片段指在JSP页面中嵌入的Java或脚本代码,它将在页面请求的处理期间被执行。通过Java代码可以定义变量或是流程控制语句等,通过脚本代码可以应用JSP的内置对象在页面输出内容、处理请求和响应并访问session会话等。代码片段的语法格式如下:
1 | <% Java代码或是脚本代码 %> |
代码片段的使用比较灵活,它可以是Java代码,也可以调用JSP提供的内置对象。
创建一个名为“index.jsp”的页面,在其中应用代码片段输出10的阶乘。
index.jsp文件的关键代码如下:
1 | <% |
使用JSP表达式
JSP表达式用于在页面中输出信息,它可以插入到网页的文本中用于输出文本内容,也可以插入到HTML标记中用于动态设置属性值。
JSP表达式的语法格式如下:
1 | <%= 表达式 %> |
表达式可以是任何Java语言的完整表达式,其最终运算结果将被转换为字符串。
例如,使用JSP表达式输出用户相关信息的代码如下:
1 | <% |
使用声明标识
在一个JSP页面中也可以如编写Java文件一样定义成员变量及成员方法,此种方式即声明标识的应用。使用声明标识在JSP页面中定义变量或方法是全局的,同时要求遵循Java语言的语法。
声明标识的语法格式如下:
1 | <%! 声明变量或方法的代码 %> |
由于使用声明标识声明的变量是全局的,所以在多个用户并发访问时会产生线程安全的问题,此种方式应用很少。
注释
在JSP页面中代码注释可分为基本HTML注释、隐藏注释和代码片段中的注释等,不同的注释适用于不同的位置,其作用也不同。
基本HTML注释
HTML语言是Web开发中的基础,HTML注释就是应用在HTML代码中的解释或说明性的文字,这些注释的内容并不会被浏览器解析执行。由于JSP页面中包含了HTML代码,所以在JSP页面同样可以使用HTML注释。
HTML注释的语法格式如下:
1 | <!-- 注释内容 --> |
在HTML注释中可以嵌入由JSP表达式指定的动态代码,即HTML注释还可以使用以下格式:
1 | <!-- 注释内容<%=表达式 %> --> |
例如,在一个JSP页面中添加以下注释代码:
1 | <!-- 当前时间:<%= new java.util.Date().toLocaleString()%> --> |
在JSP文件运行后通过查看HTML源代码可以得到类似的注释信息:
1 | <!-- 当前时间:2020-03-10 12:40:19 --> |
HTML注释并不是安全的注释方式,可以通过查看网页源代码的方式查看编写的注释内容。
隐藏注释
JSP提供了一种隐藏注释,JSP容器会在转换编译JSP的过程中过滤注释的内容。所以在形成的HTML代码中不会出现注释内容,此种注释方式的安全性比较高。隐藏注释的语法格式如下:
1 | <%-- 注释内容 --%> |
代码片段中的注释
在代码片段中编写注释与在Java代码中编写注释的方法相同,可分为单行与多行注释。其中单行注释以“//”开头,后面接注释内容,其语法格式如下:
1 | // 注释内容 |
多行注释以“/”开头,以“/”结束。在这个标识中间的内容为注释内容,并且注释内容可以换行。其语法格式如下:
1 | /* |
此外在JSP中也可以使用Java代码中的规范形式注释,即Java doc的注释方法,以“/*”开头并以“/”结束,其语法格式如下:
1 | /** |
JSP动作标识
在JSP 2.0规范中定义了一些标准的动作,用于为请求处理阶段提供信息。如操作JavaBean、包含其他文件和执行请求转发等,这些动作在请求处理阶段按照在页面中出现的顺序执行。由于JSP动作标识基于XML语法实现,所以在JSP页面中只需要遵循XML语法调用即可。
JSP动作标识的通用语法格式如下:
1 | <标识名 属性1="值1" 属性2="值2".../> |
或:
1 | <标识名 属性1="值1" 属性2="值2"...> |
使用包含动作标识jsp:include
jsp:include动作标识用于包含其他页面,被包含的页面可以是动态页面或静态页面。jsp:include包含的原理是将被包含的页面编译处理后将结果包含在页面中,包含页面的过程如图所示。
当浏览器第1次请求一个使用jsp:include包含其他页面的页面时,Web容器首先会编译被包含的页面。然后将编译处理后的返回结果包含在页面中,之后编译包含页面,最后将两个页面组合的结果回应给浏览器。
由于静态页面不需要编译即可被Web容器解析,所以如果被包含的页面是一个静态页面,将不会经历编译处理这一过程。
jsp:include动作标识的语法格式如下:
1 | <jsp:include page="url" flush="false" /> |
或:
1 | <jsp:include page="url" flush="false"> |
(1)page属性:指定被包含文件的相对路径。例如,指定属性值为“top.jsp”,则表示将与当前JSP文件相同文件夹中的top.jsp文件包含到当前JSP页面中。
(2)flush属性:可选,设置是否刷新缓冲区,默认为false。如果设置为true,在当前页面输出使用缓冲区的情况下首先刷新缓冲区,然后执行包含操作。
使用请求转发的动作标识jsp:forward
jsp:forward动作标识将当前请求转发到其他Web资源(HTML页面、JSP页面和Servlet等),在执行请求转发之后当前当前页面将不再执行,而是执行该标识指定的目标页面。执行请求转发的基本流程如图所示。
jsp:forward动作标识的语法格式如下:
1 | <jsp:forward page="url"/> |
或:
1 | <jsp:forward page="url"> |
page属性指定请求转发的目标页面,该属性值可以是一个指定文件路径的字符串或表示文件路径的JSP表达式。
使用jsp:forward请求转发被转向到的目标资源必须与当前JSP页面处于同一上下文应用环境中,否则会出现页面找不到的错误。
使用子动作标识jsp:param
JSP的动作标识jsp:param可以作为其他标识的子标识,用于为其他标识传递参数,其语法格式如下:
1 | <jsp:param name="参数名" value="参数值"/> |
(1)name属性:指定参数名称。
(2)value属性:设置对应的参数值。
例如,通过jsp:param标识为jsp:forward标识指定参数,可以使用下面的代码:
1 | <jsp:forward page="update.jsp"> |
在上面的代码中实现了在请求转发到update.jsp页面的同时传递参数userId,其值为1。
通过jsp:param动作标识指定的参数将以“参数名=值”形式添加到请求中,其功能与在文件名后面直接加“?参数名=参数值”相同。
使用动作标识jsp:useBean
使用jsp:useBean动作标识可以在JSP页面中创建一个Bean实例,并且通过属性设置可以将该实例保存在JSP中的指定范围内。如果在指定的范围内已经存在指定的Bean实例,那么将使用这个实例,而不会重新创建。通过jsp:useBan标识创建的Bean实例可以在Scriptlet中应用。
该标识的语法格式如下:
1 | <jsp:useBean |
也可以在标识体内嵌入子标识或其他内容:
1 | <jsp:useBean id="变量名" scope="page--request--session--application"...> |
1.id属性
该属性指定一个变量,在定义的范围内或Scriptlet中将使用该变量来引用创建的Bean实例。该变量必须符合Java中变量的命名规则。
2.type属性
该属性用于设置由id属性指定的变量的类型,它可以指定要创建实例的类本身、类的父类或者是一个接口。
使用type属性来设置变量类型的语法格式如下:
1 | <jsp:useBean id="us" type="com.Bean.UserInfo" scope="session"/> |
如果在session范围内已经存在名为“us”的实例,则将该实例转换为type属性指定的UserInfo类型(必须是合法的类型转换)并赋值给id属性指定的变量;若指定的实例不存在,将抛出下面的异常:
1 | bean us not found within scope |
上述用法的jsp:useBean标识被转换为如下对应的Servlet代码:
1 | com.Bean.UserInfo us =null; |
3.scope属性
该属性指定创建Bean实例的存取范围,省略该属性时的值为“page”。执行jsp:useBean标识首先会在scope属性指定的范围来查找指定的Bean实例,如果该实例已经存在,则引用这个Bean;否则重新创建,并将其保存在scope属性指定的范围内。scope属性的可选值如下。
(1)page:指定创建的Bean实例只能在当前的JSP文件中使用,包括在通过include指令静态包含的页面中有效。
(2)request:指定创建的Bean实例可以在请求范围内存取,在请求被转发至的目标页面中可通过request对象的getAttribute(“id属性值”)方法获取创建的Bean实例。一个请求的生命周期是从客户端向服务器发出一个请求到服务器响应这个请求给用户后结束,请求结束后保存在其中的Bean实例失效。
(3)session:指定创建Bean实例的有效范围为session,session是当用户访问Web应用时,服务器为用户创建的一个对象,服务器通过session的id值来区分其他用户。对某一个用户而言,在该范围中的对象可被多个页面共享。可以使用session对象的getAttribute(“id属性值”)方法获取创建的Bean实例。
也可以使用session对象的getValue(“id属性值”)来获取,但不建议使用该方法。
(4)application:指定创建的Bean实例的有效范围从服务器启动开始到服务器关闭结束。application对象在服务器启动时创建,被多个用户共享,所以访问该对象的所有用户共享保存在该对象中的Bean实例。
可以使用application对象的getAttribute(“id属性值”)方法获取创建的Bean实例。
4.class属性
class属性指定一个完整的类名,其中package表示类包的名称;className表示类的Class文件名称。通过class属性指定的类不能是抽象的,必须具有公共且没有参数的构造方法。在未设置type属性时,必须设置class属性。
使用class属性定位一个类的语法格式如下:
1 | <jsp:useBean id="us" class="com.Bean.UserInfo" scope="session"/> |
程序首先会在session范围中来查找是否存在名为“us”的UserInfo类的实例,如果不存在,则会通过new操作符实例化UserInfo类来获取一个实例,并以“us”为实例名保存在session范围内。上述用法的jsp:useBean标识被转换为如下对应的Servlet代码:
1 | com.Bean.UserInfo us =null; |
代码中的_jspx_page_context对象为JSP中的pageContext内置对象。
5.class=”package.className” type=”数据类型”
class与type属性可以指定同一个类,在jsp:useBean标识中组使用时的格式如下:
1 | <jsp:useBean id="us" class="com.Bean.UserInfo" type="com.Bean.UserBase" scope="session"/> |
这里假设UserBase类为UserInfo类的父类。该标识被执行时程序首先创建一个以type属性值为类型和以id属性值为名称的变量us,并赋值为null。然后在session范围内来查找这个名为“us”的Bean实例,如果存在,则将其转换为type属性指定的UserBase类型(类型转换必须是合法的)并赋值给变量us;否则通过new操作符来实例化一个UserInfo类的实例并赋值给变量us,最后将us变量存储在session范围内。
上述用法的jsp:useBean标识被转换为如下对应的Servlet代码:
1 | com.Bean.UserBase us =null; |
6.beanName=”package.className” type=”数据类型”
beanName与type属性可以指定同一个类,在jsp:useBean标识中二者一起使用时的格式如下:
1 | <jsp:useBean id="us" beanName="com.Bean.UserInfo" type="com.Bean.UserBase"/> |
这里假设UserBase类为UserInfo类的父类。该标识被执行时程序首先创建一个以type属性值为类型,以id属性值为名称的变量us,并赋值为null。然后在session范围内来查找这个名为“us”的Bean实例,如果存在,则将其转换为type属性指定的UserBase类型(类型转换必须是合法的)并赋值给变量us;否则通过instantiate()方法从UserInfo类中实例化一个类并将其转换为UserBase类型后赋值给变量us,最后将变量us存储在session范围内。
上述用法的jsp:useBean标识被转换为如下对应的Servlet代码:
1 | com.Bean.UserBase us =null; |
通常情况下应用jsp:useBean标识的如下格式:
1 | <jsp:useBean id="变量名" class="package.className"/> |
如果需要在多个页面中共享这个Bean实例,可将scope属性设置为“session”。
在页面中使用jsp:useBean标识来实例化一个Bean实例后,可以通过jsp:setProperty属性来设置或修改该Bean中的属性,或者通过jsp:getProperty标识来读取该Bean中指定的属性。
使用动作标识jsp:getProperty
jsp:getProperty属性用来从指定的Bean中读取指定的属性值并输出到页面中,该Bean必须具有getXXX()方法。
jsp:getProperty标识的语法格式如下:
1 | <jsp:getProperty name="Bean实例名" property="propertyName"/> |
(1)name属性:指定一个某JSP范围中的Bean实例。jsp:getProperty标识将会按照page、request、session和application的顺序来查找这个Bean实例,直到第1个实例被找到。若任何范围内不存在这个Bean实例,则会抛出下面的异常:
1 | Attempted a bean operation on a null object |
(2)property属性:指定要获取由name属性指定的Bean中的哪个属性值。若指定的值为“userName”,那么Bean中必须存在getUserName()方法;否则会抛出下面的异常:
1 | Cannot find any information on property 'userName' in a bean of type '此处为类名‘ |
如果指定Bean中的属性是一个对象,那么调用该对象的toString()方法并输出执行结果。
使用动作标识jsp:setProperty
jsp:setProperty标识通常情况下与jsp:useBean标识一起使用,它调用Bean中的setXXX()方法将请求中的参数赋值给由jsp:useBean标识创建的JavaBean中对应的简单属性或索引属性。该标识的语法格式如下:
1 | <jsp:setProperty |
jsp:setProperty标识中的属性如下。
(1)name属性
name属性指定一个存在JSP中某个范围中的Bean实例。jsp:setProperty标识将会按照page、request、session和application的顺序来查找这个Bean实例,直到找到第1个实例。若任何范围内不存在这个Bean实例,则会抛出异常。
(2)property=”*”
property属性值为“*”,则request请求中所有参数的值将被一一赋给Bean中与参数具有相同名称的属性。如果请求中存在空值的参数,那么Bean中对应的属性将不会被赋值为null;如果Bean中存在一个属性,但请求中没有与之对应的参数,那么该属性同样不会被赋值为null,在这两种情况下的Bean属性都会保留原值或默认值。
这种使用方法要求请求中的参数名和类型必须与Bean中的属性名和类型一致,但由于通过表单传递的参数都是String类型,所以JSP会自动将这些参数转换为Bean中对应的属性类型。
(3)property=”propertyName”
property属性取值为Bean中的属性,则只将request请求中与该Bean属性同名的一个参数的值赋给这个Bean属性。
更进一步讲,如果property属性指定的Bean属性为“userName”,那么指定Bean中必须存在setUserName()方法;否则会抛出类似下面的异常:
1 | Cannot find any information on property 'userName' in a bean of type 'com.Bean.UserInfo' |
在此基础上,如果请求中没有与“userName”同名的参数,则该Bean属性会保留原值或默认值,而不会被赋值为null。</br.
当请求中参数的类型与Bean中属性类型不一致时,JSP会自动进行转换。
(4)property=”propertyName”param=”parameterName”
param属性指定一个request请求中的参数,property属性指定Bean中的某个属性。这种使用方法允许将请求中的参数赋值给Bean中与该参数不同名的属性。如果param属性指定的参数值为空,那么由property属性指定的Bean属性会保留原值或默认值,而不会被赋为null。
(5)property=”propertyName” value=”值”
其中value属性指定的值可以是一个字符串数值或表示一个具体值的JSP表达式或EL表达式,该值将被赋给property属性指定的Bean属性。
当value属性指定一个字符串且指定的Bean属性与其类型不一致时,则将该字符串值自动转换为对应的类型。
当value属性指定一个表达式时,那么该表达式所表示的值的类型必须与property属性指定的Bean属性一致;否则会抛出下面的异常:
1 | argument type mismatch |