自定义标签的目的是简化java代码,一个自定义标签对应着一段Java代码
如下例子,希望通过自定义标签获取到客户端的IP
流程1.首先有对应的自定义标签的接口SimpleTag,它的实现类SimpleTagSupport,我们自定义的类就继承与SimpleTagSupport类,然后在自定义类的doTag()方法里敲写自己想要的功能代码
流程2.定义这样获取客户端的自定义标签类如下
package com.swust.customTag;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.jsp.JspContext;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.SimpleTagSupport;
//定义标签处理器:获取客户端ID
public class CoutomeTag extends SimpleTagSupport {
public void doTag() throws JspException, IOException {
//获取PageContext,目的通过PageContetxt来获取request
PageContext con = (PageContext)this.getJspContext();
ServletRequest request = con.getRequest();
//获取客户端ID
String Addr = request.getRemoteAddr();
//获取到标准输出流
//首先获取到响应对象
ServletResponse resp = con.getResponse();
PrintWriter out = resp.getWriter();
out.println(Addr);
}
}
流程三.注册该自定义标签,对比前章自定义EL函数,在一个后缀为.tld结尾的xml文件里进行配置
配置文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<!-- 头部注释如下 -->
<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
version="2.0">
<!-- 定义标标签信息 -->
<tlib-version>1.0</tlib-version>
<short-name>ct</short-name>
<uri>http://www.ct.com</uri>
<tag>
<name>ClientIP</name>
<tag-class>com.swust.customTag.CoutomeTag</tag-class>
<body-content>empty</body-content> //确定标签的标签体是否为空
</tag>
</taglib>
使用方法如下:
<ct:ClientIP/>
定义带有标签体的标签
流程类似与前面自定义标签的三个步骤, 1.定义实现标签功能的类继承与SimpleTagSupport 2.在配置文件中注册该类
1.定义实现标签功能的类继承与SimpleTagSupport
//定义标签处理器:需求:将标签体里面的字母转为大写
public class CoutomeTag extends SimpleTagSupport {
public void doTag() throws JspException, IOException {
//创建一个输出流,主要目的是获取标签体的字符串内容
StringWriter sw = new StringWriter();
//获取到jsp标签体
JspFragment jspBody = this.getJspBody();
//获取到jsp的输出流
JspWriter out = this.getJspContext().getOut();
//将标签体的内容都写到sw输出流中
jspBody.invoke(sw);
//将sw输出流里面的内容转换为字符串
String content = sw.toString();
content = content.toUpperCase();
out.println(content);
}
}
2.在配置文件中注册该类
<?xml version="1.0" encoding="UTF-8"?>
<!-- 头部注释如下 -->
<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
version="2.0">
<!-- 定义标标签信息 -->
<tlib-version>1.0</tlib-version>
<short-name>ct</short-name>
<uri>http://www.ct.com</uri>
<tag>
<name>ClientIP</name>
<tag-class>com.swust.customTag.CoutomeTag</tag-class>
<!--
标签体内容的几个写法:
1.empty:<表示标签体为空>
2.scriptless:表示当前标签具有标签体,但是标签体中不能出现java脚本(java代码块,jsp表达式),但是可以出现EL表达式
3.jsp:(已过时不能使用)
4.tagdependent:当前标签j具有标签体。将标签体内容原样显示到浏览器,即使标签中写的是EL,也不会对El进行计算
-->
<body-content>scriptless</body-content>
</tag>
</taglib>
带属性的标签:
标签的属性
<form action="LoginServlet" method = "POST"></form> 这其中action和method就是form标签的属性
流程对比上面的自定义标签,以及带标签体的自定义标签。流程分别是定义对应的功能类,注册该类
在带属性的标签中重点掌握:标签的属性,反应到标签处理器就是set属性
需求文件如下:
以下是在文件里注册对应的信息
综合使用例子
第一例:
需求:自定义标签用来遍历List
对照上面的流程
编写对应功能的类
注册到tld文件
1.jsp中的请求代码
<%
LinkedList<String> list = new LinkedList<String>();
list.add("s1");
list.add("s2");
list.add("s3");
pageContext.setAttribute("listtest", list);
%>
<ct:foreach list = "${pageScope.listtest}" name = "name">${name } <br></ct:foreach>
可以看到自定义的标签要有,list和name两个属性,属性都小写,同时标签体里还有el表达式
实现遍历list的功能类如下
public class ForeachList extends SimpleTagSupport {
private LinkedList list;
private String name; //通过set方法获取属性
public void setList(LinkedList List) {
this.list = List;
}
public void setName(String name) {
this.name = name;
}
public void doTag() throws JspException, IOException {
for(Object obj:list) {
this.getJspContext().setAttribute(name, obj); //这顿代码是将遍历到的list的内容,放到域里面,原因:因为标签体里是一个el表达式,要输出得先将内容放在el表达式中去
this.getJspBody().invoke(null); //这行代码的饿意思是直接将jsp标签体的内容直接写到输出流中
}
}
}
第二例:
需求:在第一例的基础上,定义foreach,能够完成map,set,list,数组的遍历
流程跟上面一样分为几步
1.编写对应功能的类,以下代码是将遍历四种数据的方式写在了一个方法里
2.jsp文件中的代码
注意基本数据类型数组的遍历,比如int[] 等等,遍历的方法得把每个数据单独的取出来再进行遍历,具体的代码如下,涉及到反射机制,以及不能直接用foreach循环,需要用到for(;;)循环,因为我们不知道数组内部具体的数据类型
示例代码如下
功能里面的代码,主要是看如何处理数组数据的
//首先判断data是否为一个数组
if(data.getClass().isArray() ) {
//创建一个list,目的是把数组里的数据往里面存放
List list = new ArrayList();
for(int i = 0;i<Array.getLength(data);i++) {
list.add(Array.get(data, i));
}
return list;
}
还可以将自定义的标签打包发行
以后再使用的时候,可以直接使用