2.8.4 带属性的标签

2.8.4 带属性的标签

前面的简单标签既没有属性,也没有标签体用法、功能都比较简单。实际上还有如下两种常用的标签。

  • 带属性的标签
  • 带标签体的标签。

正如前面介绍的,带属性标签必须为每个属性提供对应的settrgettr方法。带属性标签的配置方法与简单标签也略有差别,下面介绍一个带属性标签的示例:

QueryTag.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package lee;

import javax.servlet.jsp.tagext.*;
import javax.servlet.jsp.*;
import java.io.*;
import java.sql.*;

public class QueryTag extends SimpleTagSupport {
// 定义成员变量来代表标签的属性
private String driver;
private String url;
private String user;
private String pass;
private String sql;

// driver的setter和getter方法
public void setDriver(String driver) {
this.driver = driver;
}

public String getDriver() {
return this.driver;
}

// url的setter和getter方法
public void setUrl(String url) {
this.url = url;
}

public String getUrl() {
return this.url;
}

// user的setter和getter方法
public void setUser(String user) {
this.user = user;
}

public String getUser() {
return this.user;
}

// pass的setter和getter方法
public void setPass(String pass) {
this.pass = pass;
}

public String getPass() {
return this.pass;
}

// sql的setter和getter方法
public void setSql(String sql) {
this.sql = sql;
}

public String getSql() {
return this.sql;
}

// 执行数据库访问的对象
private Connection conn = null;
private Statement stmt = null;
private ResultSet rs = null;
private ResultSetMetaData rsmd = null;

// conn的setter和getter方法
public void setConn(Connection conn) {
this.conn = conn;
}

public Connection getConn() {
return this.conn;
}

// stmt的setter和getter方法
public void setStmt(Statement stmt) {
this.stmt = stmt;
}

public Statement getStmt() {
return this.stmt;
}

// rs的setter和getter方法
public void setRs(ResultSet rs) {
this.rs = rs;
}

public ResultSet getRs() {
return this.rs;
}

// rsmd的setter和getter方法
public void setRsmd(ResultSetMetaData rsmd) {
this.rsmd = rsmd;
}

public ResultSetMetaData getRsmd() {
return this.rsmd;
}


public void doTag() throws JspException, IOException {
try {
// 注册驱动
Class.forName(driver);
// 获取数据库连接
conn = DriverManager.getConnection(url, user, pass);
// 创建Statement对象
stmt = conn.createStatement();
// 执行查询
rs = stmt.executeQuery(sql);
rsmd = rs.getMetaData();
// 获取列数目
int columnCount = rsmd.getColumnCount();
// 获取页面输出流
Writer out = getJspContext().getOut();
// 在页面输出表格
out.write("<table border='1' bgColor='#9999cc' width='400'>");
// 遍历结果集
while (rs.next()) {
out.write("<tr>");
// 逐列输出查询到的数据
for (int i = 1; i <= columnCount; i++) {
out.write("<td>");
out.write(rs.getString(i));
out.write("</td>");
}
out.write("</tr>");
}
} catch (ClassNotFoundException cnfe) {
cnfe.printStackTrace();
throw new JspException("自定义标签错误" + cnfe.getMessage());
} catch (SQLException ex) {
ex.printStackTrace();
throw new JspException("自定义标签错误" + ex.getMessage());
} finally {
// 关闭结果集
try {
if (rs != null)
rs.close();
if (stmt != null)
stmt.close();
if (conn != null)
conn.close();
} catch (SQLException sqle) {
sqle.printStackTrace();
}
}
}
}

上面这个标签稍微复杂一点,它包含了5个属性,如程序中粗体字代码所示(为标签处理类定义成员变量即可代表标签的属性),程序需要为这5个属性提供settergetter方法。
该标签输出的内容依然由doTag()方法决定,该方法会根据SQL语句查询数据库,并将查询结果显示在当前页面中。

对于有属性的标签,需要为tag元素增加attribute子元素,每个attribute子元素定义一个标签属性。attribute子元素通常还需要指定如下几个子元素:

  • name:设置属性名,子元素的值是字符串内容
  • required:设置该属性是否为必需属性,该子元素的值是truefalse
  • fragment:设置该属性是否支持JSP脚本、表达式等动态内容,子元素的值是truefalse

为了配置上面的QueryTag标签,需要在mytaglib.TLD文件中增加如下配置片段。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<!-- 定义第二个标签 -->
<tag>
<!-- 定义标签名 -->
<name>query</name>
<!-- 定义标签处理类 -->
<tag-class>lee.QueryTag</tag-class>
<!-- 定义标签体为空 -->
<body-content>empty</body-content>

<!-- 配置标签属性:driver -->
<attribute>
<name>driver</name>
<required>true</required>
<fragment>true</fragment>
</attribute>
<!-- 配置标签属性:url -->
<attribute>
<name>url</name>
<required>true</required>
<fragment>true</fragment>
</attribute>
<!-- 配置标签属性:user -->
<attribute>
<name>user</name>
<required>true</required>
<fragment>true</fragment>
</attribute>
<!-- 配置标签属性:pass -->
<attribute>
<name>pass</name>
<required>true</required>
<fragment>true</fragment>
</attribute>
<!-- 配置标签属性:sql -->
<attribute>
<name>sql</name>
<required>true</required>
<fragment>true</fragment>
</attribute>
</tag>

上面代码分别为该标签配置了driverurluserpasssql五个属性,并指定这5个属性都是必需属性,而且属性值支持动态内容.
配置完毕后,就可在页面中使用标签了,先导入标签库,然后使用标签。使用标签的JSP页面片段如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<%@ page contentType="text/html; charset=UTF-8" language="java" errorPage="" %>
<!-- 导入标签库,指定mytag前缀的标签,
由http://www.crazyit.org/mytaglib的标签库处理 -->
<%@ taglib uri="http://www.crazyit.org/mytaglib" prefix="mytag"%>
<!DOCTYPE html>
<html>
<head>
<title>自定义标签示范</title>
</head>
<body bgcolor="#ffffc0">
<h2>下面显示的是查询标签的结果</h2>
<!-- 使用标签 ,其中mytag是标签前缀,根据taglib的编译指令,
mytag前缀将由http://www.crazyit.org/mytaglib的标签库处理 -->
<mytag:query
driver="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/javaee"
user="root"
pass="32147"
sql="select * from news_inf"/><br/>
</body>
</html>

测试

在浏览器中浏览该页面,效果如图2.35所示。

JSP页面中只需要使用简单的标签,即可完成“复杂”的功能:执行数据库查询,并将查询结果在页面上以表格形式显示。这也正是自定义标签库的目的以简单的标签,隐藏复杂的逻辑。
当然,并不推荐在标签处理类中访问数据库,因为标签库是表现层组件,它不应该包含任何业务逻辑实现代码,更不应该执行数据库访问,它只应该负责显示逻辑。

第三方标签库

  • JSTLSun提供的一套标签库,这套标签库的功能非常强大。
  • 另外,DisplayTagApache组织下的一套开源标签库,主要用于生成页面并显示效果