简单标签的属性
在上一小节中,实现了一个具有防盗链功能的<itcast:antiHotLinking/>标签,当请求消息头中referer请求头字段的值不符合判断条件时,标签会将用户的访问请求重定向到index.html页面。如果多个JSP页面都需要这样的防盗链功能,则需要重定向到不同的页面。这时,<itcast:antiHotLinking/>标签很难满足需求。为了提高标签的灵活性和复用性,在JSP页面使用自定义标签时,可以通过设置属性为标签处理器传递参数信息。例如,可以为<itcast:antiHotLinking />标签增加一个url属性,通过该属性指定重定向的页面,具体示例如下:
<itcast:antiHotLinking url = "/chapter09/index.html" />
要想为自定义标签设置属性,通常需要完成两件任务,具体如下:
1、在标签处理器类中,为每一个属性定义对应的成员变量并定义setter()方法
自定义标签每个属性都必须按照JavaBean的属性定义方式,例如标签中有一个属性名为url,在标签处理器类中就必须定义一个与之对应的方法setUrl()。当JSP容器调用标签处理器对象的doTag()方法之前,将依次调用每个属性对应的setter()方法,将各个属性值传递给标签处理器类。
默认情况下,自定义标签的属性值为静态文本,当setter()方法的参数为String类型时,JSP容器会直接将属性值作为一个字符串传递给该方法。如果setter()方法中的参数类型为基本数据类型,JSP容器在调用setter()方法之前会先将属性值进行转换。例如在JSP页面中使用了如下所示的标签:
<itcast:test attr = "123" />
而标签处理器类中定义的setter方法如下所示:
public void setAttr(int attr)
当JSP容器在处理attr属性时,会先调用Integer. value("123")方法将字符串“123”转换为整数123,之后再作为参数传递给标签处理器类的setAttr()方法。
2、在TLD文件中声明每个标签的属性信息
在TLD文件中,<tag>标签有一个子元素<attribute>用于描述自定义标签的属性,自定义标签的每个属性都必须要有一个对应的<attribute>元素。在<attribute>元素中还包含了一些子元素,表1列举了<attribute>的一些子元素,具体如下:
表1 <attribute>的子元素
元素名 | 功能描述 |
---|---|
description | 用于描述属性的描述信息 |
name | 用于指定属性的名称,属性名大小写敏感,且不能以jsp、_jsp、java、和sun开头 |
required | 用于指定在JSP页面调用自定义标签时是否必须设置这个属性。其取值包括true和false,true表示必须设置,false表示设不设置均可。默认值为false |
rtexprvalue | rtexprvalue是runtime expression value(运行时表达式)的简称,用于指定属性的值为静态还是动态。其取值包括true和false,true表示属性值可以为一个动态元素,比如一个脚本表达式<%=value%>,false表示属性值只能为静态文本值,比如“abc”。默认值为false |
type | 用于指定属性值的类型 |
在表1列举的5个元素中,<name>子元素用于指定属性的名称,其值必须进行设置,而且属性名称一定要和jsp页面中自定义标签属性名一致,其它的子元素则可以设置也可以不用设置。
接下来,对上一小节的<itcast:antiHotLinking/>标签进行修改,为其增加一个url属性,具体实现步骤如下所示:
(1)修改例1中定义的标签处理器类AntiHotLinking.java,为其增加一个成员变量url和一个成员方法setUrl(String url),如例1所示。
例1 AntiHotLinking.java
1 package cn.itcast.chapter09.simpletag;
2 import java.io.IOException;
3 import javax.servlet.http.*;
4 import javax.servlet.jsp.JspException;
5 import javax.servlet.jsp.PageContext;
6 import javax.servlet.jsp.tagext.*;
7 public class AntiHotLinking extends SimpleTagSupport {
8 private String url;
9 public void setUrl(String url) {
10 this.url = url;
11 }
12 public void doTag() throws JspException, IOException {
13 // 获得JSP页面的pageContext对象
14 PageContext pageContext = (PageContext) this.getJspContext();
15 // 获得request对象
16 HttpServletRequest request = (HttpServletRequest) pageContext
17 .getRequest();
18 // 获得请求的超链接所网页的URL
19 String referer = request.getHeader("referer");
20 // 拼写本机的请求消息头
21 String serverName = "http://" + request.getServerName();
22 // 输出访问页面的URL
23 System.out.println(referer);
24 // 判断请求消息头的值不为空且请求头与本机头字段信息相同
25 if (referer != null && referer.startsWith(serverName)) {
26 // 执行JSP页面内容
27 } else {
28 try {
29 // 获取响应对象
30 HttpServletResponse resp =
31 (HttpServletResponse)pageContext.getResponse();
32 // 将请求重定向到本地资源index.html页面
33 resp.sendRedirect(url);
34 } catch (Exception e) {
35 e.printStackTrace();
36 }
37 }
38 }
39 }
在例1中,当JSP容器解析到标签的url属性时,会调用setUrl()方法将属性值传递给成员变量url,这样在程序的第33行就可以根据调用者指定的url属性值来决定要重定向到哪个页面。
(2)为描述<itcast:antiHotLinking />标签的<tag>标签增加子元素<attribute>,如下所示:
<tag>
<name>antiHotLinking</name>
<tag-class>
cn.itcast.chapter09.classisctag.AntiHotLinking
</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>url</name>
<required>true</required>
</attribute>
</tag>
在上面的<attribute>元素中,通过<name>子元素指定标签的属性为url,由于标签处理器类需要根据url属性的值决定重定向的页面,因此将<required>子元素的值设置为true,即在JSP页面调用标签时,必须指定url属性。
(3)修改antiHotLinking.jsp页面,为其中的<itcast:antiHotLinking />标签增加url属性,如下所示:
<itcast:antiHotLinking url = "/chapter09/index.html" />
(4)启动Tomcat服务器,在浏览器中输入URL地址http://localhost:8080/chapter09/antiHotLinking.jsp
访问antiHotLinking.jsp页面,由于referer头字段为空,因此标签根据url属性的值将请求重定向到指定的index.html页面,如图1所示。
图1 访问antiHotLinking.jsp页面
从图1可以看出,我们已经成功的为<itcast:antiHotLinking/>标签增加了一个url属性。
:动手体验:为标签属性设置JSP动态元素
在TLD文件中,如果将<rtexprvalue>元素的值设置为true,则标签的属性值可以被设置为一个JSP动态元素,这是一个非常有用的功能,它使得标签的属性值不再局限于静态文本,而可以根据程序的需求动态地进行设置。例如标签中有一个名为user的属性,这个属性接收cn.itcast.chapter09.domain.User类型的值,而在页面的session域中以“user”为键保存了一个User类型的对象,那么在JSP页面中可以使用EL表达式来设置标签的user属性值,如下所示:
<itcast:showtime user = "${user }" />
需要注意的是,当自定义标签的属性值为JSP动态元素时,JSP容器在处理标签属性时不会对属性的值进行转换,而是直接将其传递给标签处理器类,所以在这种情况下,JSP动态元素的结果类型必须与处理器类中属性的类型相同,否则会出现编译错误。
接下来就根据上面的需求设计一个自定义标签<itcast: showtime user = "" />,在标签中定义一个user属性接收cn.itcast.chapter09.domian.User类型的值。
(1)在chapter09工程下,创建一个cn.itcast.chapter09.domain包,并在该包中定义一个User类,在类中定义一个name属性,如例2所示。
例2 User.java
1 package cn.itcast.chapter09.domain;
2 public class User {
3 //定义name字段
4 private String name;
5 //提供set和get方法
6 public String getName() {
7 return name;
8 }
9 public void setName(String name) {
10 this.name = name;
11 }
12 }
(2)在chapter09工程下的cn.itcast.chapter09.classisctag包中编写标签处理器类Showtime.java,在类中定义一个User类型的成员变量user以及一个setUser(User user)方法,如例3所示。
例3 Showtime.java
1 package cn.itcast.chapter09.simpletag;
2 import java.io.IOException;
3 import javax.servlet.jsp.JspException;
4 import javax.servlet.jsp.JspWriter;
5 import javax.servlet.jsp.PageContext;
6 import javax.servlet.jsp.tagext.SimpleTagSupport;
7 import cn.itcast.chapter09.domain.User;
8 public class Showtime extends SimpleTagSupport {
9 //定义user属性
10 private User user;
11 //提供setter方法
12 public void setUser(User user) {
13 this.user = user;
14 }
15 public void doTag() throws JspException {
16 //获取pageContext对象
17 PageContext pageContext = (PageContext) this.getJspContext();
18 //获取out对象
19 JspWriter out = pageContext.getOut();
20 try {//输出用户名
21 out.write("当前用户的名字:" + user.getName());
22 } catch (IOException e) {
23 e.printStackTrace();
24 }
25 }
26 }
(3)在simpletag.tld文件中增加一个Tag元素,对标签处理器类Showtime进行注册,注册信息如下所示:
<tag>
<name>showtime</name>
<tag-class>cn.itcast.chapter09.simpletag.Showtime</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>user</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
由于标签<itcast: showtime user = "" />中的user属性接收一个JSP动态元素,因此在<attribute>元素中设置子元素<rtexprvalue>的值为true。
(4)编写JSP页面showtime.jsp,在页面中首先使用脚本片段在session域中存入一个User对象,并设置User对象的name属性值,然后使用<itcast:showtime user = "${user }" />标签,在标签中使用EL表达式将session域中的User对象传给user属性。showtime.jsp页面如例4所示。
例4 showtime.jsp
1 <%@ page language="java" pageEncoding="GBK"
2 import="cn.itcast.chapter09.domain.User"%>
3 <%@taglib uri="/simpleTag" prefix="itcast"%>
4 <html>
5 <head>
6 <title>showtime Tag</title>
7 </head>
8 <body>
9 <%--向User对象中存值--%>
10 <%
11 User user = new User();
12 user.setName("Conca");
13 session.setAttribute("user", user);
14 %>
15 <itcast:showtime user="${user }" />
16 </body>
17 </html>
(5)启动Tomcat服务器,在浏览器地址栏输入URL地址http://localhost:8080/chapter09/showtime.jsp
访问showtime.jsp页面,可以看到浏览器中显示出session域中User对象的name属性值,如图2所示。
图2 访问antiHotLinking.jsp页面