目录
8.3.3.The choose/when/otherwise Tag
1.JSP概述
JSP页面其实就是一个Servlet。但使用起来比编写Servlet要容易得多。
JSP页面是在JSP容器中运行的。Servlet容器一般也是JSP容器。例如Tomcat就是一个Servlet/JSP容器。
2.注释(comment)
JSP页面中可以使用两种注释:JSP注释、HTML注释。
2.1.JSP注释
以开头,以结尾。例如:
<%-- 这是一个JSP注释 --%>
JSP注释不会被发送到浏览器,也不能够嵌套。
<!-- 这是一个HTML注释 -->
HTML注释会被发送到浏览器。
Servlet容器将几个对象传递给它所运行的Servlet。例如,在Servlet的service方法中获得HttpServletRequest和HttpServletResponse,并在init方法中获得ServletConfig。此外,还可以通过HttpServletRequest对象调用getSession方法获得一个HttpSession。
在JSP中,可以通过使用隐式对象的方式来获取这些对象。
对象 |
类型 |
request |
javax.servlet.http.HttpServletRequest |
response |
javax.servlet.http.HttpServletResponse |
out |
javax.servlet.jsp.JspWriter |
session |
javax.servlet.httpHttpSession |
application |
javax.servlet.ServletContext |
config |
javax.servlet.ServletConfig |
pageContext |
javax.servlet.jsp.PageContext |
page |
javax.servlet.jsp.HttpJspPage |
exception |
java.lang.Throwable |
3.2.request对象
request对象表示由Servlet/JSP容器传给Servlet的service方法的HttpServletRequest对象。可以像使用HttpServletRequest对象的引用一样使用request。
如,以下代码是从HttpServletRequest对象中获取userName参数:
<% String userName = request.getParameter("userName"); %>
3.3.out对象
out对象引用javax.servlet.jsp.JspWriter,它类似于在HttpServletResonse中调用getWriter()之后得到的java.io.PrintWriter。可以调用它的print方法重载PrintWriter,将消息发送到浏览器。
3.4.pageContext对象
pageContext是指为页面创建的javax.servlet.jsp.PageContext。它提供了一些方法可以访问request、response等对象,不过这些方法用处不大,因为我们可以通过隐式对象来访问这些对象。
真正有用的是PageContext允许利用Expression Language访问这些对象。
PageContext提供的另一些重要的方法是那些存取属性,如getAttribute和setAttribute方法。属性可以保存在以下四种范围中:page、request、session以及application。
page范围最窄,保存在这里的属性只能在同一个JSP页面中使用。
request范围是指当前的ServletRequest。
session范围是指当前的HttpSession。
application范围是指ServletContext。
4.指令(directive)
指令是一种JSP句法元素,它告诉JSP转换器应该如何将某个JSP页面转换成Servlet。
JSP 2.2中定义了几个指令:page、include、taglib、tag、attribute以及variable。
其中最重要的是:page和include。
4.1.page指令
语法
<%@ page attribute1="value1" attribute2="value2" ... %>
@和page之间的空格是可选的,attribute1、attribute2等都是page指令的属性。
4.1.1.page指令的属性
import
指定要导入的一种或多种Java类型,供本页的Java代码所用。
导入List接口:
<%@ page import="java.util.List" %>
利用通配符*可以导入整个包:
<%@ page import="java.util.*" %>
导入多重类型时,两种类型之间要用逗号隔开:
<%@ page import="java.util.ArrayList, java.util.Calendar, java.io.PrintWriter" %>
下面这些包的是隐式导入的:
javax.servlet.*; javax.servlet.http.*; javax.servlet.jsp.*;
怎么知道它们是隐式导入的呢?只要查看一个由JSP生成的Servlet类,即可得知。
session
值为true时,表示这个页面参与Session管理;
值为false时,表示不参与Session管理。
默认值为true,意味着如果之前还没有javax.servlet.http.HttpSession实例,那么调用这个JSP页面时会创建一个。
buffer
指定隐式对象out的缓冲区大小,以千字节为单位。强制以kb为后缀。
缓冲区的默认容量大于或等于8kb,具体取决于JSP容器。
这个属性还可以设置为none,表示不适用缓存,但这样会导致输出的内容直接被写入相应的PrintWriter。
autoFlush
默认值为true,表示当缓冲区满时,被缓存的输出应当自动刷新。
值为false时,表示只有在调用隐式对象response的flush方法时,才进行刷新缓冲区。因此,当缓冲区益处时,就会抛出一个异常。
isThreadSafe
表示页面中实现的线程安全级别。建议JSP的作者不要使用这个属性,因为它会产生一个包含不建议使用的代码的Servlet。
info
指定所生成的Servlet的getServletInfo方法的返回值。
errorPage
表示负责处理该页面可能会出现的错误的页面。
isErrorPage
表名这个页面是否负责处理错误。
contentType
指定该页面隐式对象response的内容类型,其默认值为text/html。
pageEncoding
指定该页面的字符编码,其默认值为ISO-8859-1。
isElIgnored
表名是否忽略EL表达式。
language
指定这个JSP页面使用的脚本语言,其默认值为java,这个值是JSP 2.2中唯一有效的值。
extends
指定这个JSP页面的实现类必须扩展的超类。该属性很少使用。
deferredSyntaxAllowedAsLiteral
指明是否允许使用字符序列“#{”作为该页面和编译单元的String字面值。
默认值为false。
与EL表达式有关。
trimDirectiveWhitespaces
表名是否从输出内容中删除只包含空格的模板文本。
默认值为false。
4.1.2.用法
page指令可以出现在页面中的任何位置。只是当它包含contentType或者pageEncoding属性时,它必须放置在所有的模板数据之前,并且是在利用Java代码发送任何内容之前。因为必须在发送任何内容之前设置内容类型和字符编码。
page指令可以多次出现。但是在多个page指令中多次出现的同一个属性,它的值必须一致,只有import属性除外。
4.2.include指令
利用include指令可以将另一个文件的内容放到当前的JSP页面中。在一个JSP页面中可以使用多个include指令。
如果某部分特殊的内容需要被其他页面所用,或者被处于不同位置的某个页面所用,那么将这部分内容做成一个include文件是很有帮助的。
语法
<%@ include file="url" %>
此处@和include之间的空格是可选的,并且url是表示一个include文件的相对路径。
如果url以一个正斜线(/)开头,那么其在服务器中就会被解读成是一条绝对路径。
如果不是以正斜线开头,则会被解读为相对于当前JSP页面的路径。
5.脚本元素(scripting element)
脚本元素是JSP的一种句法,它将Java代码合并成一个JSP页面。
脚本元素有三种类型:Scriptlet、声明和表达式。
5.1.Scriptlet
Scriptlet是一段Java代码块,它以<%开头,以%>结束。
CODE
<%@ page import="java.util.Enumeration"%> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Scriptlet example</title> </head> <body> <b>Http headers:</b><br/> <%-- first scriptlet --%> <% for (Enumeration<String> e = request.getHeaderNames(); e.hasMoreElements(); ) { String header = e.nextElement(); out.println(header + ": " + request.getHeader(header) + "<br />"); } String message = "Thank you."; %> <hr /> <%-- second scriptlet --%> <% out.println(message); %> </body> </html>
解析
上述JSP页面中有两个Scriptlet。注意,在一个Scriptlet中定义的变量,对于它后面的其他Scriptlet是可见的。
5.2.表达式
表达式的运算结果会被填入隐式对象out的print方法中。
表达式以<%开头,并以%>结束。
例子:
Today is <%=java.util.Calendar.getInstance().getTime()%>
注意,表达式后面不需要分号。
对于这个表达式,JSP容器会先运算java.util.Calendar.getInstance().getTime(),然后将结果传给out.print()。因此,它与下面这个Scriptlet的结果是一样的:
Today is <%= out.print(java.util.Calendar.getInstance().getTime()); %>
5.3.声明
声明能够在JSP页面中使用的变量和方法。声明凡在<%! %>标签中间。
CODE
<%! public String getTodayDate() { return new java.util.Date(); } %> <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Declarations</title> </head> <body> Today is <%=getTodayDate() %> </body> </html>
5.4.关闭脚本元素
随着JSP 2.0中的Expression Language的发展,建议做法是使用EL表达式来访问服务器端的对象,而不是在JSP页面中编写Java代码。
因此,原本开启的JSP 2.0脚本元素,可以通过在部署描述符的<jsp-property-group>中定义一个scripting-invalid元素,将其关闭。
例子:
<jsp-property-group> <url-pattern>*.jsp</url-pattern> <scripting-invalid>true</scripting-invalid> </jsp-property-group>
6.动作(action)
动作也是JSP中的句法,它们被编译成执行某个操作的Java代码,例如访问某个Java对象,或者调用某个方法。
6.1.include
include动作用于动态的包含另一个资源,它可以包含另一个JSP页面、一个Servlet或者一个静态的HTML页面。
例子
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Include action</title> </head> <body> <jsp:include page="jspf/menu.jsp"> <jsp:param name="text" value="How are you?" /> </jsp:include> </body> </html>
include指令和include动作的区别
使用include指令时,这种包含是发生在页面转换的时候,例如JSP容器将页面转换成一个Servlet的时候。
使用include动作时,这种包含则是发生在请求的时候。因此,可以利用include动作传递参数。
使用include指令时,被包含资源的文件扩展名并不重要。
使用include动作时,文件扩展名必须为jsp,以便它能够将其作为一个JSP页面进行处理。
6.2.forward
forward动作是将当前页面跳转到另一个不同的资源。
例如,下面的forward动作就是将当前页面跳转到login.jsp页面:
<jsp:forward page="jspf/login.jsp"> <jsp:param name="text" value="Please login" /> </jsp:forward>
7.EL表达式
7.1.EL语法
EL表达式是以${开头,以}结束。一个EL表达式的构造如下:
${ expression }
访问对象属性:
${ object["propertyName"] }
${ object.propertyName }
7.2.EL隐式对象
在一个JSP页面中南,可以通过JSP脚本访问JSP隐式对象。但是如果要编写无脚本的JSP页面,那么就不能访问这些隐式对象了。
EL通过提供一组它自己的隐式对象,可以用来访问各种对象。
EL隐式对象清单
对象 |
描述 |
pageContext |
当前JSP页面的javax.servlet.jsp.PageContext |
initParam |
包含所有context初始化参数并以参数名称作为键的Map |
param |
包含所有请求参数并以参数名称作为键的Map。每个键的值就是指定名称的第一个参数值。因此,如果有两个同名的请求参数,将只有第一个参数可以利用param对象获取到。要想或有所有同名参数的值,则要使用params对象。 |
paramValues |
包含所有请求参数并以参数名称作为键的Map。每个键的值就是包含所有指定名称的一个字符串数组。如果该参数只有一个值,它仍然会返回一个只有一个元素的数组。 |
header |
包含所有请求标头并以标头名称作为键的Map。每个键的值就是指定标头名称的第一个标头。换句话说,如果某个标头有多个值,那将只返回第一个值。想要获得多值标头,则要使用headerValues对象。 |
headerValues |
包含所有请求标头并以标头名称作为键的Map。每个键的值就是包含指定标头名称所有值的一个字符串数组。如果一个标头只有一个值,也将返回一个只有一个元素的数组。 |
cookie |
包含当前请求对象中所有Cookie对象的Map。Cookie的名称就是Map的键,每一个键都映射到一个Cookie对象。 |
applicationScope |
包含ServletContext对象中所有属性并以属性名称作为键的Map |
sessionScope |
包含HttpSession对象中所有属性并以属性名称作为键的Map |
pageContext
pageContext对象表示当前JSP页面的javax.servlet.jsp.PageContext。它包含所有的JSP隐含对象。
8.JSTL
JavaServer Pages Standard Tag Library(JSTL)是一个定制标签类库的集合,用于解决一些常见的问题,例如迭代一个映射或者集合、条件测试、XML处理,甚至数据库访问和数据操作等。
8.1.下载JSTL
需要下载两个包:JSTL API和JSTL实现。JSTL API中包含javax.servlet.jsp.jstl包,由JSTL规范中定义的类型组成。JSTL实现则包含了相关的实现类。必须将两个jar包都加入项目才能使用。
如果使用的是Servlet容器(如Tomcat、Jetty),那么其中不会包含这两个包,必须是Java EE应用服务器才行,例如WildFly、TomEE,和GlassFish。
下载Java EE应用程序服务器,然后从其中的lib目录下找到这两个包。
例如:
Apache TomEE 7.0.1
apache-tomee-webprofile-7.0.1libopenejb-jstl-1.2.jar
GlassFish 4.1.1
glassfish4glassfishmodulesjavax.servlet.jsp.jstl.jar
glassfish4glassfishmodulesjavax.servlet.jsp.jstl-api.jar
WildFly 9.0.2
wildfly-9.0.2.Finalmodulessystemlayersasejavaxservletjstlapimainjboss-jstl-api_1.2_spec-1.1.2.Final.jar
从这几个服务器中找到列出的相应的包即可,任选任何一个服务器下的包即可,因为他们是遵循同一个标准编写的。
有的服务器下面只有一个包是因为其将JSTL API和JSTL实现编译到一个jar文件中了。
Core
变量支持、流向控制、URL管理、其他
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
I18n
语言环境、消息格式化、数字和日期格式化
<%@ taglib prefix="f" uri="http://java.sun.com/jsp/jstl/fmt"%>
Functions
集合、字符串操作
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
为URL拼接当前上下文路径
<img alt="" src="<c:url value="/images/logo.png" />">
对某个条件进行测试,如果条件成立则处理标签内的主体内容,否则不处理。
可以使用 var 属性设置域变量名,使用 scope 属性指定其作用范围
<c:if test="${detail.todo.status == 0}"> <option value="0">待办</option> </c:if>
8.3.3.The choose/when/otherwise Tag
分支语句结构,类似于 switch 语句结构
<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>
用于迭代一个集合对象
可以迭代的对象
java.util.Collection 的实现
java.util.Map 的实现
对象或者基本类型的数组
java.util.Iterator
java.util.Enumeration
有两种用法,一种是将标签中的内容重复一定的次数,另一种是迭代一个集合对象
重复内容
<c:forEach [var="varName"] begin="begin" end="end" step="step"> body content </c:forEach>
迭代集合
<c:forEach items="collection" [var="varName"] [varStatus="varStatusName"] [begin="begin"] [end="end"] [step="step"]> body content </c:forEach>
属性
var
String
引用当前迭代项目的域变量名称
items
支持的任何类型
要迭代的对象集合
varStatus
String
保存迭代状态的域变量名称,它的值类型为 javax.serlet.jsp.jstl.core.LoopTagStatus
begin
int
如果指定了items,那么迭代将从处于指定索引的项开始,该集合中的第一个项索引为0
如果没有指定items,迭代将从该值设定的索引开始,并且begin的值必须大于等于0
end
int
如果指定了items,那么迭代结束处于指定索引的项(包括该项)
如果没有指定items,那么当索引到达指定值时,迭代结束
step
int
步长,迭代会从集合的第一个step开始,根据step步长逐个进行
如果设置step属性,必须大于等于1
用于格式化日期
<f:formatDate value="${detail.todo.createDate}" pattern="yyyy-MM-dd HH:mm:ss" />