Java Server Pages(JSP)规范用于组合Java代码和HTML,以提供网页的动态内容。当创建动态内容时,编写JSP比编写HTTP Servlet更方便,因为JSP允许将Java代码直接嵌入到HTML页,而对于HTTPServlet,则需要将HTML嵌入到Java代码中。JSP还可以调用一种称为标记库(taglib)的自定义Java 类(使用类似于HTML的标记)。
通过JSP,可以将网页的动态内容及静态演示内容分开。它可以满足两种不同类型的开发人员:负责网页图形设计的HTML开发人员和负责软件开发以创建动态内容的Java开发人员。
BES应用服务器支持JSP 1.1规范、JSP标记库、JSTL和JSP预编译。
1.1.2.1 标记
表2‑3 JSP标记
JSP标记 | 语法 | 描述 |
Scriptlet | 嵌入Java源代码Scriptlet。Java代码会被执行,其输出也会按顺序插入该页的其余HTML中。 | |
指令 | <%@ dir-type dir-attr %> | 指令包含向应用程序服务器发出的消息。 |
声明 | <%! declaration %> | 对页中其它声明、Scriptlet或表达式引用的变量或方法进行声明。 |
表达式 | <%= expression %> | 定义一个Java表达式,该表达式在请求页面时进行计算,并会转换为字符串,然后内联发送到JSP响应的输出流。 |
操作 | <jsp:useBean ... > <jsp:setProperty ...> <jsp:getProperty ...> <jsp:include ...> <jsp:forward ...> <jsp:plugin ... > | 提供对JSP高级功能的访问,并且仅仅使用XML语法。 |
注释 | <%/* comment */%> | 通过仅使用JSP注释标记,确保注释会从可查看的HTML文件源代码中删除。当用户在浏览器中选择“查看源文件”时,HTML注释保持可见状态。 |
JSP规范中定义了一些隐式Java对象,为JSP页提供有用的方法和信息。隐式对象仅在Scriptlet或表达式中才可以使用,在声明里定义的方法中使用这些关键字会导致转换时发生编译错误。
request代表HttpServletRequest对象。它包含有关来自浏览器的请求的信息,并具有若干可用于获取Cookie、头和会话数据的有用方法。
response代表HttpServletResponse对象。它提供用于设置从JSP页发回到浏览器的响应信息的方法。这些响应的信息包含Cookie和其它头信息。
但不能在JSP页内部使用response.getWriter()方法;如果这样做,会引发运行时异常。要将JSP 响应发送回浏览器,请在Scriptlet代码中直接使用out对象。
out是javax.jsp.JspWriter的实例,具有几个可用于将输出发送回浏览器的方法。
pageContext代表javax.servlet.jsp.PageContext对象。便于访问各种作用域的名称空间和与Servlet相关的对象,并且它为与Servlet相关的常用功能提供包装方法。
session代表请求的javax.servlet.http.HttpSession对象。默认情况下,session指令设置为true,因此在默认情况下,session是有效的。JSP2.1 规范声明,如果session指令设置为false,使用session关键字则会导致致命转换错误。
application代表javax.servlet.ServletContext对象。使用它可找到有关Servlet引擎和Servlet环境的信息。
要转发或包含请求,可使用ServletContext访问Servlet requestDispatcher,也可使用JSPforward指令将请求转发至其它Servlet,以及使用JSP include指令来包含来自其它Servlet的输出。
config代表javax.servlet.ServletConfig对象,并提供对Servlet实例初始化参数的访问。
page代表从此JSP页生成的Servlet实例。在Scriptlet代码中使用时,它与Java关键字this同义。
要使用page,必须将其转换为实现JSP页的Servlet的类类型,因为它被定义为java.lang.Object的实例。默认情况下,Servlet类是按JSP文件名命名的。为方便起见,建议使用Java关键字this(而不是使用page)引用Servlet实例和获得对初始化参数的访问。
指令可指示JSP执行特定功能,或以特殊方式解释JSP页。指令由某个指令类型和该类型的一个或多个特性组成。指令可以放置在JSP页的任何位置,位置通常是无关的(除了include指令);并且可以在一个JSP页中使用多个指令标记。
指令的语法为<%@dir_type dir_attr %>,dir_type表示指令类型,dir_attr表示使用该指令类型的一个或多个指令特性的列表。指令的类型有三种:page、taglib或include。其中使用page指令可以设置字符编码;使用taglib指令可声明JSP页使用的自定义JSP标记扩展。
使用声明可在生成的JSP Servlet的类作用域级别定义变量和方法。在JSP标记之间做出的声明可从JSP页中的其它声明和Scriptlet进行访问。例如:
int i=0;
String foo="Hello";
private void bar(){
……
}
%>
JSP Scriptlet组成JSP Servlet的HTTP响应的Java正文。要将Scriptlet包含在JSP页中,请使用此处显示的标记:
// Java代码
%>
1. 可将多个Scriptlet Java代码块与纯HTML混合在一起。
2. 可在任何位置(甚至在Java构造块中)切换HTML和Java代码。
3. 可使用预定义的变量out将HTML文本从Java代码直接输出到Servlet输出流。
表达式经常用于返回用户以前提供的数据,表达式可以让HTML在JSP页中更具可读性。要将表达式包含在JSP文件中,请使用以下标记:
使用JSP操作可以创建、使用、修改由JavaBean代表的对象,也可以转发或包含其它请求,或包含Applet。
通过<jsp:useBean>操作标记,可以实例化符合JavaBean规范的Java对象,并可以从JSP页引用这些对象。
<jsp:useBean>标记会从特定作用域检索现有的指定Java对象,如果找不到现有对象,它会实例化新对象,并将其与由id特性给定的名称相关联。对象存储在由scope特性给定的位置中,该特性确定该对象的可用性。例如,以下标记会尝试从HTTP会话检索类型为examples.jsp.ShoppingCart、名为cart的Java对象。
<jsp:useBeanid="cart" class="examples.jsp.ShoppingCart"scope="session"/>
如果当前不存在这样的对象,则JSP会尝试新建一个对象,并将其命名为cart,存储在HTTP会话中。
<jsp:useBean>标记语法具有另一种格式,通过该格式,可以在首次实例化对象时设置某些属性。例如:
<jsp:useBeanid="cart" class="examples.jsp.ShoppingCart"scope=session>
<jsp:setPropertyname="cart" property="cartName"value="music"/>
</jsp:useBean>
实例化JavaBean对象之后,可通过其id名称,在JSP文件中将其作为Java对象进行引用。可在Scriptlet标记和表达式计算器标记中使用它,并可分别使用<jsp:setProperty>和<jsp:getProperty>标记调用其setXxx()或getXxx()方法。
使用scope特性可指定JavaBean对象的可用性和生命周期。作用域可以是下列隐式对象之一:page、request、session、application。
可使用<jsp:include>标记将其它资源包含在JSP中。
JSF2.0和JSTL1.2包是WEB应用通用的库,BES应用服务器默认提供了JSF实现(BES_HOME\framework\components\javax.faces.jar)和JSTL(BES_HOME\framework\components\javax.servlet.jsp.jstl.jar),使用JSF或JSTL功能的所有标准WEB应用都可以直接使用JSF和JSTL。
JSF技术简化了为JavaServer应用生成用户界面的过程。利用JSF快速生成WEB应用的步骤是:
1. 将可重用的UI组件装配到页面中;
2. 将组装进来的UI组件连接到应用数据源;
3. 将客户端生成的事件绑定到服务器端事件处理程序。
1.1.3.2 JavaServerPage标准标记库(JSTL)
JSP标准标记库(JSTL)将许多WEB应用中常见的核心功能作为简单的标记进行封装。JSTL可支持常见的、结构化的任务,例如迭代和条件、用于操作XML文档的标记、国际化标记以及SQL标记。它还提供了一个框架,用于将现有自定义标记与JSTL标记集成。
1.1.4 自定义标记库(Taglib)
JSP标记能封装Java逻辑或功能,从而将Java逻辑和页面展现分离开来、简化JSP页面的开发和维护。JSP除了使用JSP标准标记库(JSTL)之外,也可以自定义标记。
一组相关的自定义标记可以以标记库(TagLibrary)的形式发布。每个Taglib都包含一个标记库描述符(TLD)文件,以及各个标记的处理实现类和辅助类。标记库的结构如下图所示:
图1‑1 标记库结构
开发自定义标记库的步骤为:
1.1.4.1 开发标记处理类
当使用了自定义标记的JSP页面被调用时,WEB容器会调用标记处理类。
标记处理类必须实现javax.servlet.jsp.tagext.Tag或javax.servlet.jsp.tagext.BodyTag接口,或者继承javax.servlet.jsp.tagext.TagSupport或javax.servlet.jsp.tagext.BodyTagSupport。
标记处理类的简单示例如下:
package com.bes.demo;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspTagException;
importjavax.servlet.jsp.tagext.BodyTagSupport;
public class SimpleTag extendsBodyTagSupport {
// 遇到开始标记时调用,此处接收JSP页面传递过来的name属性,并打印欢迎语句
public intdoStartTag() throws JspException {
try{
pageContext.getOut().print("Hello," + this.name + "!");
}catch (Exception ex) {
thrownew JspTagException("SimpleTag: " + ex.getMessage());
}
returnSKIP_BODY;
}
// 遇到结束标记时调用
public intdoEndTag() {
returnEVAL_PAGE;
}
// 标记的每个属性都需定义getter、setter方法
private Stringname = null;
public StringgetName() {
return(this.name);
}
public voidsetName(String name) {
this.name= name;
}
}
1.1.4.2 编写标记库描述符
标记库描述符(TLD)是描述标记库的XML文档,包含了标记库的整体信息和每个标记的信息。WEB容器使用标记库描述符校验标记。标记库描述符必须以.tld为文件扩展名,存放在WEB应用的WEB-INF目录或其子目录中。
下面是一个简单的TLD文件示例:
<?xml version="1.0"encoding="UTF-8"?>
<taglib>
<tlib-version>1.0</tlib-version>
<jsp-version>1.2</jsp-version>
<short-name>bes-tags</short-name>
<!-- 定义Taglib的URI,JSP页面使用taglib指令声明该Taglib。taglib指令的uri需与此uri元素值保持一致 -->
<uri>/simpleTag</uri>
<tag>
<name>hello</name>
<tag-class>com.bes.demo.SimpleTag</tag-class>
<body-content>empty</body-content>
<attribute>
<name>name</name>
<required>yes</required>
<rtexprvalue>yes</rtexprvalue>
</attribute>
</tag>
</taglib>
1.1.4.3 使用自定义标记库
WEB应用要使用标记库,需要将标记处理类放在WEB应用的WEB-INF/lib或WEB-INF/classes目录中,将TLD文件放在WEB应用的WEB-INF目录或其子目录中。
在JSP页面中,使用taglib指令声明标记库。taglib指令的uri属性需与TLD文件中的<uri>值保持一致;prefix属性用来定义标记库的前缀,编写JSP时使用此前缀引用标记库中的标记。JSP页面示例如下:
<%@ taglib uri="/simpleTag"prefix="simple" %>
<simple:hello name="World"/>
该WEB应用部署后,访问JSP时WEB容器会调用com.bes.demo.SimpleTag的setName方法将name赋值为World,然后调用doStartTag()方法,在页面上输出如下内容:
Hello, World!