JSP学习笔记

JSP概述

JSP是构建在Java Web应用程序上的第二种技术,是Servlet技术的补充,JSP页面本质上是一个Servlet。

当一个JSP页面第一次被请求的时候,Servlet/JSP容器主要做以下两件事情:

  1. 转换JSP页面到JSP页面实现类,该实现类就是一个Servlet
  2. 如果转换成功,Servlet/JSP容器随后编译该Servlet类,并装载和实例化该类,然后和其他正常Servlet一样执行生命周期

JSP页面可以包含模板数据和语法元素。这里,语法元素是一些具有特殊意义的JSP转换符。例如,”<%”是一个元素,表示java代码块的开始,”%>”也是一个元素,表示java代码块的结束,<%…%>块被称为scriplet。除去语法元素外的一切是模板数据,模板数据会原样发送给浏览器。

隐式对象

Servlet容器会传递几个对象给它运行的Servlet,例如HttpServletRequest和HttpServletResponse对象,等等。在JSP中,同样可以通过隐式对象来访问这些对象。如下图所示:

特别说明的是,PageContext中提供了用于获取和设置属性的方法,即getAttribute方法和setAttribute方法。属性值可以被存储为4个范围之一:页面、请求、会话和应用程序:

  • PAGE_SCOPE:最小范围,存储的属性只能在用一个JSP页面可用
  • REQUEST_SCOPE:当前的ServletRequest范围
  • SESSION_SCOPE:当前的HttpSession范围
  • APPLICATION_SCOPE:当前的应用程序范围

指令

指令是一种JSP语法元素的类型,指示JSP转换器如何翻译JSP页面为Servlet。

page指令

通过page指令来控制JSP转换器转换当前JSP页面的某些方面。例如,可以告诉JSP用于转换隐式对象out的缓冲器的大小,内容类型,以及需要导入的Java类型,等等。

page指令的语法:

<%@ page attribute1=”value1” attribute2=”value2” …%>

以下列举一些常见的page指令属性:

  • import:定义一个或多个页面中将被导入和使用的java类型。
  • buffer:以KB为单位,定义隐式对象out的缓冲大小,该值可以为none,表示没有缓冲,所有数据直接写入PrintWriter
  • autoFlush:默认值为true,表示当缓冲满时会自动写入输出流。而值为false,表示仅当调用隐式对象out的flush方法时,才会写入输出流
  • contentType:定义本页面隐式对象response的内容类型,默认是text/html

错误处理

使用page指令的的isErrorPage属性(值为true)来标识一个JSP页面是错误处理页面。其他需要防止未捕获的异常的页面使用page指令的errorPage属性来指向错误处理页面即可。

include指令

可以使用include指令将其他文件中的内容包含到当前的JSP页面。

include指令语法:
<%@ include file = “url”%>

url为被包含文件的相对路径,若url以一个斜杠(/)开始,则该url为文件在服务器上的绝对路径,否则为当前JSP页面的相对路径。

脚本元素

脚本程序也是JSP的语法元素,是一个java代码块,以符号<%开始,符号%>结束。但是,随着JSP2.0对表达式语言的加强,在JSP页面中使用EL访问服务器端对象且不写Java代码,所以可以禁用脚本元素。关于脚本元素在这就不多做介绍了。

动作

动作是JSP第三种类型的语法元素,可以被转换成java代码来执行操作,如访问一个java对象或调用方法,除了标准之外,还可以创建自定义标签执行某些操作。

介绍一些常见的动作:

1.useBean:创建一个关联Java对象的脚本变量。例如,下面代码将创建一个java.util.Date实例,并赋值给名为today的脚本变量。

1
<jsp:useBean id="today"class="java.util.Date"/>

2.setProperty和getProperty:setProperty动作用于对一个Java对象设置属性,getProperty则输出Java对象的一个属性。

1
2
3
<jsp:useBean id="employee"class="test.Employee"/>
<jsp:setProperty name="employee" property="firstname"value="Abigail"/>
<jsp:getProperty name="employee" property="firstname"/>

3.include:用来动态地引入另一个资源,可以引入一个JSP页面,一个Servlet或者一个静态的HTML页面。

1
2
3
<jsp:include page = "url">
<jsp:param name="text"value="How are you"/>
</jsp:include>

include指令与include动作的区别:对于include指令,资源引入发生在JSP容器将页面转换成为Servlet的时候。对于include动作,资源引入发生在页面请求时,因此,include动作可以传递参数。

4.forward:将当前页面转向到其他资源

1
2
3
<jsp:forward page = "url">
<jsp:param name="text"value="How are you"/>
</jsp:forward>

表达式语言

表达式语言(Expression Language):用户用它来访问应用程序数据,编写免脚本的JSP页面。

EL语法

EL表达式以 ${开头,以}结束。结构:${expression}
例如,若a+b=8,c+d=10,那么 ${a+b} ${c+d}的计算结果为字符串类型的”810”

为了访问对象的属性,可以使用以下任意一种形式:
${object[“propertyName”]}
${object.propertyName}

但是,如果propertyName不是有效的Java变量名,只能使用[]运算符。

在EL表达式中,想要访问List,Array,Map对象的某个元素,使用expr-a[expr-b]形式的表达式。假设,expr-a为java.util.Map,expr-a[expr-b]会查看expr-b是否为Map中的一个key,若是,则返回expr-a.get(expr-b),若不是,则返回null。

EL隐式表达式

EL表达式中的函数

在EL表达式,可以使用function标签库中函数,为了使用这些函数,必须在JSP的最前面使用以下taglib指令:
<%@ tablig uri=”http://java.sun.com/jsp/jstl/functions“ prefix=”fn”%>

调用格式:
${fn:functionName},这里functionName是函数名

下面介绍一些常用的函数:

  • contains(string,substring):测试一个字符串中是否包含指定的子字符串
  • endsWith(string,suffix):测试一个字符串是否以指定的后缀结尾
  • escapeXml(string):将字符串进行XML转义,保证该字符串能正确被XML解析器解析出来
  • indexOf(string,substring):返回指定子字符串在某个字符串中第一次出现时的索引
  • join(array,separator):将一个string数组中的所有元素合并成为一个字符串,并用指定的分隔符分开
  • split(array,delimeters):将字符串按照给定的分隔符分隔开,返回一个字符串数组
  • replace(string,beforeSubstring,afterSubstring):将字符串中出现的所有beforeString用afterString替换
  • trim(string):用于删除一个字符串开头和结尾的空白

JSTL

JSP标准标签库(JavaServer Pages Standard Tag Library,JSTL)是一个定制标签库的集合。用来解决像遍历Map或集合,条件测试,XML处理,甚至数据库访问和数据操作等常见的问题。

JSTL标签库:

在JSP页面中使用JSTL库,必须通过taglib指令

<%@ taglib uri=”uri” prefix=”prefix”%>

例如,要使用Core库,必须在JSP页面开头处做以下声明:
<%@ taglib uri=”http://java.sun.com/jsp/jstl/core“ prefix=”c”%>

一般行为

下面介绍Core标签库中常用的一般行为:out,set,remove

out标签

out标签将结果输出到当前的JspWriter,out的语法有以下两种形式,一种有body content和没有body content:

1
2
3
4
<c:out value="value" [default="defaultValue"]/>
<c:out value="value">
default value
</c:out>

out中的default属性可以赋一个默认值,当赋予其value属性的EL表达式返回null时,就会显示默认值,如果default值返回null,out就会显示一个空字符串。

set标签

set标签可以完成以下工作:

  • 创建一个字符串和一个引用该字符串的有界变量
  • 创建一个引用现存有界对象的有界变量
  • 设置有界对象的属性

set标签用法:
1.创建字符串和一个引用该字符串的有界变量

1
2
3
4
<c:set var="varName" value="value" [scope="{page|request|session|application}"] />
<c:set var="varName" [scope="{page|request|session|application}"]>
body content
</c:set>

2.设置有界对象的属性值

1
<c:set target="target" property="propertyName" value="value"/>

注意上面的target属性中必须要用一个EL表达式引用这个有界变量
例如,下面set标签将字符串”Beijing”赋予有界对象address的city属性:

1
<c:set target="${address}" property="city">Beijing</c:set>

remove标签

remove标签用于删除有界变量,但是有界变量引用的对象不能删除,语法如下:

1
<c:remove var="varName" [scope="{page|request|session|application}"]/>

条件行为

条件行为用于处理页面输出取决于特定输入值的情况,对应Java语言中的if,if…else和switch语法。

if标签

if标签是对某一个条件进行测试,假设结果为True,就处理它的body content,测试结果保存在Boolean对象中,并创建有界变量来引用这个Boolean对象。

1
2
3
<c:if test="testCondition" [var="varName"] [scope="{page|request|session|application}"]>
body content
</c:if>

choose、when和otherwise标签

choose、when和otherwise类比与Java语言中的switch、case和default。

举个例子就明白了:

1
2
3
4
5
6
7
8
9
10
11
12
13
<c:choose>
<c:when test="${param.status=="full"}">
You are a full member
</c:when>
<c:when test="${param.status="student"}">
You are a student member
</c:when>
<c:otherwise>
Please register
</c:otherwise>
</c:choose>

遍历行为

当需要遍历一个对象集合时,遍历行为就很有帮助。JSTL提供了forEach和forTokens两个执行遍历行为的标签。

forEach标签

forEach标签会固定次数重复body content或者遍历对象集合,语法如下:

1
2
3
4
5
6
7
<c:forEach [var="varName"] begin="begin" end="end" step="step">
body content
</c:forEach>
<c:forEach items="collections" [var="varName"] [varStatus="varStatusName"] [begin="begin"] [end="end"] [step="step"]>
body content
</c:forEach>

我们注意到forEach标签属性中有一个类型为javax.servlet.jsp.jstl.core.LoopTagStatus的变量varStatus,该类型描述了遍历行为的状态,例如,varStatus有count属性,返回当前遍历的次数。

forTokens标签

forTokens标签用于遍历以特定分隔符隔开的令牌,其语法如下:

1
2
3
<c:forTokens items="stringOfTokens" delims="delimiters" [var="varName"] [varStatus="varStatusName"] [begin="begin"] [end="end"] [step="step"]>
body content
</c:forTokens>

例如:

1
2
3
<c:forTokens items="A,B,C" var="item" delims=",">
<c:out value="${item}"/><br/>
<c:forTokens>

输出:
A
B
C

格式化行为

JSTL提供了格式化和解析数字与日期的标签,它们是:

formatNumber,formatData,timeZone,setTimeZone,parseNumber,parseData。

这里就不介绍细节了,需要使用到的时候去官网查询它们的标签属性。

标签文件(自定义标签)

从JSP2.0开始,通过tag file的方式,无须编写标签处理类和标签库描述文件,也能够自定义标签了。tag file在使用之前无须编译,并且不需要标签库定义文件。

tag文件必须放在应用路径的WEB-INF/tags目录下才能生效,和其他文件一样,tag文件可以被打包到jar包里。

tag file指令

和JSP页面一样,tag file可以使用指令来指挥JSP容器如何编译这个tag file。除了page指令,其他所有的JSP指令都可以用于tag file,在tag file中可以使用tag指令代替page指令

taglib 指令:用于在tag file中使用自定义标签,语法如下:
<%@ taglib uri=”tagLibraryURI” prefix=”tagPrefix”%>

attribute指令:用于设定tag file中标签的属性,将值从JSP页面传递到tag file中处理

variable指令:将tag file中的一些值传递到JSP页面,定义那些需要传递到JSP页面的变量。相对而言,attribute指令将值从JSP页面传递到tag file。

举个tag file的简单例子:

我们创建一个tag file,名称是firstTag.tag,代码如下:

1
2
3
4
5
6
7
<%@ tag import="java.util.Date" import="java.text.DateFormat"%>
<%
DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.LONG);
Date now = new Date(System.currentTimeMills());
out.println(dateFormat.format(now));
%>

下面是使用这个tag file的JSP页面代码:

1
2
<%@ taglib prefix="easy" tagdir="WEB-INF/tags"%>
Today is <easy:firstTag/>

doBody

doBody动作元素只能在tag file中使用,它用来调用一个标签的本体内容(body content)并将内容保存在一个java.lang.String类型(var属性指定)或者java.io.Reader类型(varReader属性指定)变量中。如果不指定变量,doBody动作元素会把主体内容写到JSP页面的JspWriter上。

语法如下:

1
<jsp:dobody {[var="varName"]|[varReader="varReaderName"]} scope="{page|request|session|application}"/>
0%