自从03年发布了jsp2.0之后,新增了一些额外的特性,这些特性使得动态网页设计变得更加容易。jsp2.0以后的版本统称jsp2。主要的新增特性有如下几个:
- 直接配置jsp属性
- 表达式语言(EL)
- 标签文件(Tag File)
一、直接配置jsp属性
原先我们对于jsp页面的一些属性的配置需要使用编译指令page在页面的头部指定,这就会导致在多个jsp页面中都做了同样的事情。jsp2为我们提供了一种方式,可以在web.xml中统一指定某个或者某些jsp页面的一些属性配置。主要的可配置的jsp属性有:
---指定该jsp页面是否支持表达式语言
---指定该jsp页面的编码方式
--指定该页面是否允许jsp脚本
--向指定的页面隐式的包含外部文件(引入的位置在指定页面的头部)
--向指定的页面隐式的包含外部文件(引入的位置在指定页面的底部)
在web.xml中我们使用元素jsp-config来直接配置jsp属性,每个jsp-config元素下,可以由多个jsp-property-group元素,它就是用来具体配置某个或者某些jsp属性的,具体看下面的演示:
/index.jsp
false
UTF-8
false
/top.jsp
/bottom.jsp
/index2.jsp
true
UTF-8
true
/top.jsp
/bottom.jsp
其中url-pattern元素用来指定哪些jsp页面将被应用以下配置,可以是单个jsp页面,也可以是一组jsp页面。el-ignored元素指定该页面是否支持表达式语言(接下来会说),默认是false表示支持EL。page-encoding元素指定了页面的编码方式,等效于jsp页面page编译指令中contentType属性中charset部分。scripting-invalid元素指定了页面是否支持jsp脚本,默认为false表示支持。include-prelude和include-coda元素我们分别隐式引用了外部文件,一个放在原页面的头部,另一个则是放在尾部。我们看看这两个页面:
<%@ page contentType="text/html;charset=UTF-8" language="java" import="java.util.*" %>
top.jsp
这是头部的内容
<%@ page contentType="text/html;charset=UTF-8" language="java" import="java.util.*" %>
bottom.jsp
这是底部的内容
<%@ page contentType="text/html;charset=UTF-8" language="java" import="java.util.*" %>
index.jsp
这是index页面的内容
这是index页面的内容
这是index页面的内容
这是index页面的内容
这是index页面的内容
结果如下:
查看网页源码可以看到:
可以看到这两个元素的作用和我们jsp中的编译指令include十分相似,只是我们的include编译指令可以自己选择引入的外部文件放在被引入的jsp页面中的位置,而这两个元素则一个是引入到当前jsp页面头部,一个则是引入到当前jsp页面的底部。
二、表达式语言(EL)
表达式语言是一种简化了的数据访问方式,使用它我们可以用简单的语法来实现对数据的访问。在jsp2中,建议使用表达式语言使得jsp页面格式一致,而避免使用jsp脚本。EL的使用语法是:${expression}。在了解如何使用之前,我们先了解一下他的内置对象,这些对象也是我们使用EL的关键。
pageContext: 获取当前页面的context对象,如jspcontext,servletcontext
pageScope:用于获取page范围内的属性的值
requestScope:用于获取request范围内的属性的值
sessionScopt:用于获取session范围内的属性的值
applicationScope:用于获取application范围内的属性的值
param:用于获取请求参数的值
paramValues:用于获取请求参数的集合(数组形式)
initParam:用于获取请求web应用的初始化参数(web.xml中的)
cookie:用于获取指定的cookie
从EL的内置对象看,基本上前台需要的数据都是可以获取到的。下面演示如何使用EL获取数据。
<%@ page contentType="text/html;charset=UTF-8" language="java" import="java.util.*" %>
index
<%
request.setAttribute("a","aaaaa");
session.setAttribute("b","bbbbb");
%>
${requestScope.a}
${sessionScope.b}
以上的演示是EL的很简单的使用方法,也是利用了它的内置对象来完成对数据的访问获取。下面我们看看如何通过EL语法调用自定义函数,可以说扩充了调用自定义函数的功能使得EL更加灵活。但是允许EL调用的函数都必须是静态的(因为如果非静态的就需要创建对象来调用,违背了EL设计的初衷)。自定义函数主要有以下三个步骤:
- 定义一个具有静态方法的类,并定义一些静态方法
- 在标签库中配置可供调用的方法
- 在jsp页面中使用自定义方法
第一步比较简单,就是定义一个具有静态方法的类,第二步有点像我们的自定义标签的过程,创建一个标签库,在taglib元素下,定义一个function子元素表示一个方法。
A tag library exercising SimpleTag handlers.
1.0
SimpleTagLibrary
mytid
//定义了一个EL可调用的静态方法
sayHello //指明方法名
Test_packge.SayHello //指明类名
java.long.String sayHello(java.lang.String) //指明方法的返回值,参数情况
public class SayHello {
public static String sayHello(String s){
return "hello " + s;
}
}
<%@ page contentType="text/html;charset=UTF-8" language="java" import="java.util.*" %>
<%@ taglib prefix="fun" uri="mytid" %>
index
${fun:sayHello("walker")}
我们可以看到在EL中调用自定义方法和使用自定义标签的语法很是类似,之上我们演示了一个EL调用自定义方法的完整流程,并由此可以看出,基本上EL可以调用一切所需资源,可以调用Javabean中方法获取数据库中的数据,也可以自定义类实现具体方法供EL调用。功能很是强大。
三、标签文件(Tag File)
我们之前介绍过了自定标签的定义和使用,需要三个步骤。首先需要写一个标签处理类继承SimpleTag,然后实现doTag方法就就可以用来处理标签了,然后我们需要创建一个tld文件,在跟元素taglib中定义一个一个的tag元素,最后在jsp页面中使用。过程还是很麻烦的。jsp2.0之后,引入了标签文件,这是一个简化了的自定义标签的过程,实际上计算机内部还是将它转换成了我们自定义的三个步骤,在本节的结尾,我们会一起看看源码了解下编译器做了哪些操作。
在Tag File文件中有5个编译指令,他们是:
- taglib:用于导入其他的标签库
- include:用于导入静态页面
- tag:类似jsp页面中的page编译指令,用于指定页面的基本属性
- attribute:用于设定自定义标签的属性,值是从jsp页面传入的
- variable:可以提供jsp页面调用的变量
下面定义了一个简单的Tag file:
//在WEB-INF/tags 文件下创建一个myTag.tag标签文件
<%@ tag pageEncoding="UTF-8" import="java.util.*"%>
<%@ attribute name="bgColor"%>
<%@ attribute name="cellColor"%>
<%@ attribute name="title"%>
<%@ attribute name="bean"%>
<%@ variable name-given="time" variable-class="java.lang.String" scope="AT_BEGIN" %>
<% jspContext.setAttribute("time","now");%>
${title}
<%
List list = (List)request.getAttribute("a");
for(Object ele : list){%>
<%=ele%>
<%}%>
<%@ page contentType="text/html;charset=UTF-8" language="java" import="java.util.*" %>
<%@ taglib prefix="tags" tagdir="/WEB-INF/tags" %>
index
<%
List list = new ArrayList();
list.add("walker");
list.add("yam");
request.setAttribute("a",list);
%>
<%=time%>
我们需要始终知道的是,我们使用所有的标签,他们返回的结果都是页面片段,所以如果tag文件页面全是jsp语法就完全没有意义了。我们先从index页面看,前面引入标签库不用介绍了,只是这里需要知道我们引入的tagdir并不是这个标签文件(.tag),而是他的父目录。(这样做也是为了页面简洁,不用每个标签文件都引入一次),接着我们看,使用jsp脚本定义了一个list集合,并设置共享范围。
然后我们使用标签文件,和使用标签一样,这里的bgColor等属性是对应于我们myTag.tag文件中的attribute编译指令的,这样我们这边传入的属性的值就可以自动赋值到标签文件中了。
接下来我们看看标签文件,首先使用了tag 编译指令指定了页面片段的基本属性,如编码方式等。然后就是attribute 编译指令,用于接受jsp页面传入的属性值。至于这个variable变量的定义,我们先过(后面说)。紧接着是jsp脚本输出一个表格,不再赘述。我们看看结果:
我们之前说过,标签文件是简化了的自定义标签,最终还是会被编译成Java类,和我们之前自定义标签时候写的标签处理类差不多。我们打开Tomcat/work....一直找到你的项目的tag文件夹,在里面会发现
我们打开这个标签文件,看到一坨代码。我们注意到:
private java.lang.String bgColor;
private java.lang.String cellColor;
private java.lang.String title;
private java.lang.String bean;
public java.lang.String getBgColor() {
return this.bgColor;
}
public void setBgColor(java.lang.String bgColor) {
this.bgColor = bgColor;
jspContext.setAttribute("bgColor", bgColor);
}
....
我们看到这些代码是我们用编译指令attribute定义了的变量,经过编译之后,他们被创建成私有变量并配上set/get方法。这和我们在自定义标签处理类的时候是一样的,我们说这样可以保证jsp页面传入的属性的值可以自动的赋值给这些私有属性。(web容器干的)。我们还注意到:
这里也是一样的重写了doTag方法,同时还看到了标签文件中内置的对象有:
- request
- response
- session
- application
- config
- out
- jspContext
绕了这么一圈,我们发现所谓的标签文件本质上还是我们那一套的自定义标签的流程,只是很大一部分内容交给了编译器。简化了我们程序员的工作。
最后我们看看刚才跳过的编译指令variable,从上面的内容中我们知道,jsp页面可以通过属性传值给我们的标签文件,但是如果标签文件想要返回对象给jsp页面就需要使用到我们的variable编译指令。这个指令有几个属性需要注意下:
- name-given ---指定了该变量的名称
- variable-clas - ---指定了该变量的数据类型
- scope ---指定该变量作用范围,这里有三个值
scope的第一个值可以是AT_BEGIN,该值表示此变量可以在标签体或者向下的代码中生效,第二值可以是NESTED,该值表示此变量只能出现在标签体中,第三个可以是AT_END,该值表示此变量只能从标签结束位置以后的代码中生效。可以看到第一个值的范围最大,包含了下面两个值的范围。定义完成之后,我们可以使用jspContext.setAttribute("time","now")方法为其赋值,这样我们的jsp页面就可以使用该变量了。
本篇文章至此结束,内容很简单,深入的内容还有待作者继续学习,希望能有大神指点纠正。