JSP学习记录
JSP学习记录
1.JSP的工作原理和基础标签(什么是JSP?)
全名 Java Server Pages ,如名解释: 它是建立在 Servlet 规范之上的动态网页开发技术.
其中,HTML代码和java代码共同存在, 扩展名为.jsp
其他解释>>>
关于JSP的运行原理:
1.客户端发出请求,请求访问JSP文件.例如welcome.jsp.
2.JSP容器先将JSP文件转换成一个Java源文件(即Java Servlet源程序),在转换过程中,如果发现JSP中有任何语法错误,则中段转换过程,并向–>服务端和客户端返回出错信息.
3.如若正常转换,则JSP容器将生成的Java源文件(Servlet源程序)编译成相应的字节码文件 *.class.该class文件就是一个Servlet,Servlet容器会像处理其他Servlet一样去处理它.
4.由Servlet容器加载这个.class文件创建一个该Servlet实例(即原来JSP页面的转换结果的实例),并执行Servlet的 jspInit() 方法,该方法在Servlet的整个生命周期中只会执行一次.
5.执行 jspService() 方法来处理客户端的请求.对于每一个请求,JSP容器都会创建一个新的线程来处理它. 如果多个客户端同时请求该JSP文件,则JSP容器也会创建多个线程响应请求,使每一个客户端请求都对应一个线程. JSP运行过程中采用的这种多线程的执行方式可以极大地降低系统资源的需求,提高系统的并发量并缩短响应时间. 由于第4步生成的Servlet是常驻内存的,所以响应速度非常快.
6.如果JSP文件被修改, 则服务器将根据设置决定是否对该文件重新编译. 如果重新编译,则使用新的编译结果->取代内存中常驻的Servlet,并继续上述处理过程.
7.虽然JSP效率很高, 但第一次调用时往往需要转换和编译,所以会有轻微的延迟 .此外,由于系统资源不足等原因, JSP容器可能会以某种不确定的方式将Servlet从内存中移除. 发生时首先会调用 jspDestroy() 方法,然后Servlet实例会被加入垃圾收集处理.
8.当请求处理完成后, 响应对象由JSP容器接收, 并将HTML格式的响应信息发送回客户端.
打开你的IDE,创建一个Dynamic Web Project,(动态页面项目).一步步next,在创建初始web.xml选项上打勾.文中关于Html的内容不再深入探讨.
上面代码提到了3种脚本元素:
- JSP脚本程序 <% …脚本语句… %>
脚本程序可以包含任意量的Java语句,变量,方法或表达式,只要它们在脚本语言中是有效的.
任何文本,HTML标签,JSP元素必须写在脚本程序的外面.而在表达式中可以使用HTML标签. - JSP声明 <%! …声明内容… %>
一个声明语句可以声明一个或多个变量,方法,供后面的Java代码使用,在JSP文件中,您必须先声明这些变量和方法然后才能使用它们. - JSP表达式 <%= …表达内容… %>
一个JSP表达式中包含的脚本语言表达式,先被转化成String, 然后插入到表达式出现的地方.
由于表达式的值会被转化成String, 所以您可以在一个文本行中使用表达式而不用去管它是否是HTML标签.
表达式元素中可以包含任何符合Java语言规范的表达式,但是不能使用分号来结束表达式.
在JSP中3种脚本元素配合使用,使用java语句时,有时可以省略System,比如在<% … %>脚本程序中,是因为JSP中的隐式对象已存在于JSP) 9种如下:
名称 | 类型 | 描述 |
---|---|---|
out | javax.servlet.JspWriter | 用于页面输出 |
request | javax.servlet.http.HttpServletRequest | 得到用户请求信息 |
response | javax.servlet.http.HttpServletResponse | 服务器向客户端的响应信息 |
config | javax.servlet.ServletConfig | 服务器配置,可以取得初始化参数 |
session | javax.servlet.http.HttpSession | 用来保存用户的信息 |
application | javax.servlet.ServletContext | 所有用户的共享信息 |
page | java.lang.Object | 指当前页面转换后的Servlet类的实例 |
pageContext | javax.servlet.jsp.PageContext | JSP的页面容器 |
exception | java.lang.Throwable | 表示JSP页面所发生的异常,在错误页中才起作用 |
上面代码中,在<% page指令条目中设置新属性 buffer=”0kb” 后,输出将按照顺序,否则相反.因为其设置的0kb是设置的out对象的输入缓冲区,其为0kb后系统将直接写入Servlet引擎提供的缓冲区中.
具体看图:
隐式对象中,使用pageContext对象可以获取其他8个隐式对象.pageContext对象获取隐式对象的方法如下:
方法名 | 功能描述(隐式对象) |
---|---|
JspWriter getOut() | 获取out |
Object getPage() | 获取page |
ServletRequest getRequest() | 获取request |
ServletResponse getResponse() | 获取response |
HttpSession getSession() | 获取session |
Exception getException() | 获取exception |
ServletConfig getServletConfig() | 获取config |
ServletContext getServletContext() | 获取application |
当pageContext对象后,就可以通过上述方法获取到其他8个隐式对象了.
pageContext对象不仅提供获取隐式对象的方法,还提供了存储数据的功能.pageContext对象存储数据是通过操作属性来实现的,如下:
方法名 | 功能描述 |
---|---|
void setAttribute(String name,Object value,int scope) | 设置pageContext对象的属性 |
Object getAttribute(String name,int scope) | 获取pageContext对象的属性 |
void removeAttribute(String name,int scope) | 删除指定范围内名称为name的属性 |
void removeAttribute(String name) | 删除所有范围内名称为name的属性 |
Object findAttribute(String name) | 从4个域对象中查找名称为name的属性 |
上表中,参数name指定的是属性名称,参数scope指定的是属性的作用范围.pageContext对象的作用范围有4个值,如下:
作用范围名 | 表示范围 |
---|---|
pageContext.PAGE_SCOPE | 页面范围 |
pageContext.REQUEST_SCOPE | 请求范围 |
pageContext.SESSION_SCOPE | 会话范围 |
pageContext.APPLICATION_SCOPE | Web应用程序范围 |
需要注意的是,当使用 findAttribute() 方法查找名为name的属性时,会按照 page, request, session, application 的顺序依次进行查找. 如果找到, 则返回属性的名称, 否则返回null.
下面看下pageContext设置表示范围的值的代码:
上面案例中,虽然在设置时属性名称都为str, 但当取得后,两个属性的值是不同的,因为设置时设置的范围不同,一个是page范围,一个是request范围.这就像在Java中的局部声明一样,虽然声明的变量名相同,但是值是在各自的函数方法中使用,所以值也可以是不同的.
案例1: pageContext对象的使用:
通过上述案例,可以看出不同范围的设置值和取值.
2.JSP生命周期
理解JSP底层功能的关键就是去理解它们所遵守的生命周期.
JSP生命周期就是从创建到销毁的整个过程,类似于servlet生命周期,区别在于JSP生命周期还包括将JSP文件编译成servlet.
以下是JSP生命周期中所走过的几个阶段:
- 编译阶段
servlet容器编译servlet源文件,生成servlet类.
JSP编译
当浏览器请求JSP页面时,JSP引擎会首先去检查是否需要编译这个文件.如果这个文件没有被编译过,或者在上次编译后被更改过,则编译这个JSP文件.
编译的过程包括3个步骤:(1)解析JSP文件. (2)将JSP文件转为servlet. (3)编译servlet.
- 初始化阶段:
加载与JSP对应的servlet类,创建其实例,并调用它的初始化方法.
JSP初始化
容器载入JSP文件后,它会在为请求提供任何服务前调用 jspInit() 方法,如果您需要执行自定义的JSP初始化任务,复写 jspInit() 方法就行了,像下面这样:
一般来讲程序只初始化一次,servlet也是如此,通常情况下您可以在 jspInit() 方法中初始化数据库链接,打开文件和创建查询表.
- 执行阶段:
调用与JSP对应的servlet实例的服务方法.
JSP执行
这一阶段描述了JSP生命周期中一切与请求相关的交互行为,直到被销毁.
当JSP网页完成初始化后,JSP引擎将会调用 _jspService() 方法.
_jspService() 方法需要一个 HttpServletRequest 对象和一个 HttpServletResponse 对象作为它的参数,就像下面这样:
_jspService() 方法在每个 request 中被调用一次并且负责产生与之相对应的 response ,并且它还负责产生所有 7 个 HTTP 方法的回应, 比如 GET , POST , DELETE 等等.
- 销毁阶段:
调用与JSP对应的servlet实例的销毁方法,然后销毁servlet实例.
JSP清理(销毁)
JSP生命周期的销毁阶段描述了当一个JSP网页从容器中被移除时所发生的一切.
jspDestroy() 方法在JSP中等价于servlet中的销毁方法. 当您需要执行任何清理工作时复写 jspDestroy() 方法,比如释放数据库连接或者关闭文件夹等等.
jspDestroy() 方法的格式如下:
JSP生命周期代码实例:
启动该jsp,会看到3行大字分别显示初始化次数,响应客户请求次数和销毁次数.
然后我们会看到,jspInit()方法被执行了一次,而jspDestroy()没有被执行,_jspService()在您刷新页面时就进行++操作.(每刷新一次,响应一次操作),而有意思的是,在你打开两个该测试页面,在一个里面去刷新页面时,另一个页面也会累计该响应的值.在重启tomcat服务后该值重新返回1次响应.
3.JSP指令
JSP指令用来设置整个JSP页面相关的属性,如网页的编码方式和脚本语言.
语法格式如下:
指令可以有很多个属性, 它们以键值对的形式存在, 并用逗号隔开.
JSP中的三种指令标签:
指令 | 描述 |
---|---|
<%@ page … %> | 定义网页依赖属性,比如脚本语言,error页面,缓存需求等等 |
<%@ include … %> | 包含其他文件 |
<%@ taglib … %> | 引入标签库的定义 |
- Page指令
Page指令为容器提供当前页面的使用说明.一个JSP页面可以包含多个page指令.
Page指令语法格式:
等价的XML语法格式:
属性
下表列出与Page指令相关的属性:
属性 | 描述 |
---|---|
buffer | 指定out对象使用缓冲区的大小 |
autoFlush | 控制out对象的缓存区 |
contentType | 指定当前JSP页面的MIME类型和字符编码 |
errorPage | 指定当JSP页面发生异常时需要转向的错误处理页面 |
isErrorPage | 指定当前页面是否可以作为另一个JSP页面的错误处理页面 |
extends | 指定servlet从哪一个类继承 |
import | 导入要使用的Java类 |
info | 定义JSP页面的描述信息 |
isThreadSafe | 指定对JSP页面的访问是否为线程安全 |
language | 定义JSP页面所用的脚本语言,默认是Java |
session | 指定JSP页面是否使用session |
isELIgnored | 指定是否执行EL表达式 |
isScriptingEnabled | 确定脚本元素能否被使用 |
- Include指令
JSP可以通过include指令来包含其他文件. 被包含的文件可以是JSP文件, HTML文件或文本文件. 包含的文件就好像是该JSP文件的一部分, 会被同时编译执行.
Include指令语法格式:
Include指令中的文件名实际上是一个相对的URL. 如果您没有给文件关联一个路径, JSP编译器默认在当前路径下寻找.
等价的XML语法格式:
- Taglib指令
JSP API允许用户自定义标签,一个自定义标签库就是自定义标签的集合.
Taglib指令引入一个自定义标签集合的定义, 包括库路径, 自定义标签.
Taglib指令的语法格式:
uri属性确定标签库的位置, prefix属性指定标签库的前缀.
等价的XML语法格式:
JSP动作元素
与JSP指令元素不同的是JSP动作元素在请求处理阶段起作用. JSP动作元素是用XML语法写成的.
利用JSP动作可以动态地插入文件,重用JavaBean组件,把用户重定向到另外的页面, 为Java插件生成HTML代码.
动作元素只有一种语法,它符合XML标准:
动作元素基本上都是预定义的函数,JSP规范定义了一系列的标准动作,它用JSP作为前缀, 可用的标准动作元素如下:
语法 | 描述 |
---|---|
jsp:include | 在页面被请求的时候引入一个文件 |
jsp:useBean | 寻找或者实例化一个JavaBean |
jsp:setProperty | 设置JavaBean的属性 |
jsp:getProperty | 输出某个JavaBean的属性 |
jsp:forward | 把请求转到一个新的页面 |
jsp:plugin | 根据浏览器类型为Java插件生成OBJECT或EMBED标记 |
jsp:element | 定义动态XML元素 |
jsp:attribute | 设置动态定义的XML元素属性 |
jsp:body | 设置动态定义的XML元素内容 |
jsp:text | 在JSP页面和文档中使用写入文本的模板 |
4.EL表达式和JSTL
在JSP开发中,为了获取Servlet域对象中存储的数据, 经常需要书写很多Java代码,这样的做法会使JSP页面混乱,难以维护,为此,在JSP2.0规范中提供了EL表达式. EL是Expression Language (表达/表示语言) 的缩写, 它是一种简单的数据访问语言.
初识 EL
由于EL可以简化JSP页面的书写,因此,在JSP的学习中,掌握EL是相当重要的. 要使用EL表达式, 首先要学习它的语法. EL表达式的语法非常简单, 符号都是以” ${ ” 开始,以” } ” 结束.
需要注意: 在大括号中的表达式必须符合EL语法要求. 下面案例证明EL表达式可以简化JSP页面.
同样是获取Attribute的值,用JSP表达式 和 EL表达式 写法的简洁度上差很大!
所以EL表达式可以明显简化JSP页面的书写!从而使程序简洁易维护!
另外,当域对象里面的值不存在时,使用 EL 表达式方式获取域对象里面的值时返回空字符串.
而使用Java方式获取,返回的值时null时,会报空指针异常!!!
所以,实际开发中强烈推荐EL表达式的方式获取域对象中存储的数据.
EL中的标识符
在EL表达式中,经常需要使用一些符号来标记一些名称, 如变量名, 自定义函数名等. 这些符号被称为标识符. EL 表达式中的标识符可以由任意的大小写字母, 数字和下划线组成. 为了避免出现非法的标识符, 在定义标识符时还需要遵循以下规范 .
- 不能以数字开头.
- 不能是 EL 中的保留字, 如 and, or, gt .
- 不能是 EL 隐式对象, 如 pageContext .
- 不能包含单引号 ( ` ) , 双引号 ( ” ) , 减号 ( - ) 和正斜杠 ( / ) 等特殊字符.
下面的这些标识符都是合法的.
注意! 下面这些标识符都是 不合法 的.
EL中的保留字
保留字就是编程语言里事先定义好并赋予了特殊含义的单词. 和其他语言一样, EL表达式中也定义了许多保留字, 如 false , not 等. 接下来就列举 EL 中所有的保留字, 具体如下:
需要注意的是,EL表达式中的这些保留字不能被作为标识符, 以免在程序编译时发生错误.
EL中的变量
EL表达式中的变量就是一个基本的存储单元, EL表达式可以将变量映射到一个对象上, 具体示例如下所示:
上面,product就是一个变量, EL表达式中的变量不用事先定义就可以直接使用,例如, 表达式 ${product} 就可以访问变量 product 的值.
EL中的常量
EL表达式中的常量又称字面量, 它是不能改变的数据. 在EL表达式中包含多种常量, 接下来分别对这些常量进行介绍.
- 1.布尔常量
布尔常量用于区分一个事物的正反两面, 它的值只有两个, 分别是 true 和 false . - 2.整型常量
整型常量与Java中的十进制的整型常量相同, 它的取值范围是 Java 语言中定义的常量 Long.MIN_VALUE 到 Long.MAX_VALUE 之间,即 (-2)^63 与 2^63-1 之间的整数.
浮点数常量
浮点数常量用整数部分加小数部分表示, 也可以用指数形式表示, 例如 , 1.2E4 和 1.2 都是合法的浮点数常量. 它的取值范围是 Java 语言中定义的常量 Double.MIN_VALUE 到 Double.MAX_VALUE 之间, 即 4.9E-324 ~ 1.8E308 之间的浮点数.
没必要再继续对着书本打了…要理解. page 207