1.自定义标签
*步骤:
**编写一个实现Tag接口的Java类,把页面中的java代码移到这个java类中(标签处理器类)
**编写标签库描述符(tld)文件,在tld文件中把标签处理器描述成一个标签。
*作用:
**用于移除JSP页面中的Java代码
**实现代码的重用
2.TLD文件元素
每个自定义标签都必须在TLD文件中声明,TLD文件也是XML文件,根元素是,它包含一个或者多个标签,该元素用来声明定制标签。元素中只有元素是必须的,其他都是可选的。
TLD的一些常用属性
3.编写第一个自定义标签
实例:编写一个DateTag标签,输出系统时间
eg:
//1.编写一个DateTag.java类,继承SimpleTagSupport类
public class DateTag extends SimpleTagSupport{
//2.override doTag()方法,在该方法中,实现相应的处理逻辑
public void doTag() throws JspException{
PageContext ctx=getJspContext();
JspWriter out=ctx.getOut();
SimpleDateFormat sdf=nw SimpleDateForm("yyyy年MM月dd日");
out.println(sdf.format(new Date()));
}
}
//3.在.tld文件中描述标签
<?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.1</tlib-version>
<short-name>c</short-name>
<uri>http:www.intcast.com.cn/mytag1</uri>
<tag>
<name>date</name>
<tag-class>mytag.DateTag</tag-class>
<body-content>empty</body-content>
</tag>
</taglib>
//4.将taglib导入标签中(JSP)
<%@taglib prefix="c" uri="http:www.intcast.com.cn/mytag1"%>
<c:date/>
4.自定义标签扩展
自定义标签除了编写JSP页面,还需要在页面中引入一些逻辑,例如:
*控制JSP页面某一部分内容的执行;
*控制整个JSP页面是否执行;
*控制JSP页面内容是否重复执行;
*修改JSP页面内容输出;
*移除JSP页面的java代码。
tld文件中四种标签体类型:
EMPTY、 JSP (有标签体的情形,在JSP2.0以前使用的)|| scriptless(JSP2.0以后使用的) tagdepentend
eg:
1. jsp文件中:
<body>
<itcast:demo/>ccccc
</body>
//2 .tld文件中配置如下:
<tag>
<name>TagDemo</name>
<tag-class>com.Cecilia.ResponsewebTest.TagDemo</tag-class>
<body-content>JSP</body-content>
</tag>
<tag>
<name>TagDemo1</name>
<tag-class>com.Cecilia.ResponsewebTest.TagDemo1</tag-class>
<body-content>JSP</body-content>
</tag>
新建标签处理类:TagDemo.java
public class TagDemo extends TagSupport{
int x=5;
public void doStartTag() throws JSPException{
return Tag.Skip_BODY;
return Tag.EVAL_BODY_INCLUDE;
}
public void doEndTag() throws JSPException{
return Tag.EVAL_PAGE;
resturn Tag.SKIP_PAGE;
}
public void doAfterBody() throws JSPException{
x--;
if(x>0){
return IterationTag.EVAL_BODY_AGAIN;
}else{return IterationTag.SKIP_BODY;}
}
}
4.修改标签操作
/*
1.编写一个java标签处理类,并且继承BodyTagSupport类;
2.重写doStartTag(),返回值为BodyTag.EVAL_BODY_BUFFERED;
3.重写doEndTag(),在执行doEndTag()时调用getBodyEontent()方法得到标签体内容,并对标签体内容进行修改,最后再输出就OK。
*/
public class TagDemo1 extends BodyTagSupport{
public void doStartTag() throws JSPException{
return BodyTag.EVAL_BODY_BUFFERED;
}
public void doEndTag() throws JSPException{
BodyContent bc=this.getBodyEontent();
String content=bc.getString();
content=content.toUpperCase();
try{
this.pageContent.getOut().write(content);
}catch(Exception e){
throw new RuntimeException(e);
}
return Tag.EVAL_PAGE;
}
注意:以上使用的Tag接口、IteratorionTag接口、BodyTag接口是在JSP2.0以前使用的,在JSP2.0以后只是用一个SImpleTagSupport接口就可以完成三个标签的所有功能,在这里或许有人疑问:那我们就没必要了解和学习这三个接口啦?其实,那还是有必要的,在我们接下来要学习的框架是采用以上三个接口搭建成的,所以学习这三个接口能够有利于我们在学习框架时自己看懂源码,更好地理解框架的原理。
*基本运行原理UML图
*基本的操作方法
eg:
<body>
<sitcast:demo/>cccccc
</body>
<tag>
<name>SimpleTagdemo</name>
<tag-class>com.Cecilia.ResponsewebTest.SimpleTagdemo</tag-class>
<body-content>scriptless</body-content>
</tag>
public class SimpleTagdemo extends SimpleTagSupport{
public void doTag(){
JspFragment jf=this.getTagBody();
jf.invoke(this.getJspContext().getOut());
for(int i=0;i<5;i++){
jf.invoke(null);
}
StringWriter sw=new StringWriter();
jf.invoke(sw);
String Content=sw.toString();
content=content.toUpperCase();
this.getJspContext().getOut().write(content);
}
}
6.开发带属性的标签
eg:
<body>
<sitcast:demo/>aaaa
</body>
<tag>
<name>SimpleTagdemo</name>
<tag-class>com.Cecilia.ResponsewebTest.SimpleTagdemo</tag-class>
<body-content>scriptless</body-content>
//添加属性
<attribute>
<name>count</name>
<required>true</required>
<rtexprvalue></rtexpravlue>(如果给false,那么只能是值,如果是true,那么除了值还可以接受一个运行时表达式<%= %>)
</attribute>
//新建一个标签处理类
public class SimpleTagdemo extends SimpleTagSupport{
private int count;
public void setCount(int count){
thi.count=count;
}
public void doTag()throws JspException{
JSPFragment jf=this.getJspBody();
for(int i=0;i<count;i++){
jf.invoke(null);
}
}
}
7.如何实现使用标签控制页面逻辑
*如何实现开发防盗链的标签()?
eg:
//1.在JSP文件中body体
您好!XXXXXXXXXXXX
<a href="/ResponseWebTest/1.jsp">点我</a>
//2. .tld文件配置如下:
<tag>
<name>referer</name>
<tag-class>com.Cecilia.MyJSPTest.RefererTag</tag-class>
<body-content>empty</body-content>
<attribute>
<name>site</name>
<require>true</require>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>page</name>
<require>true</require>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
//3.创建标签处理类Referer.java
/**
* 需求:开发防盗链的标签
* @author 芷若初荨
*
*/
public class RefererTag extends SimpleTagSupport{
private String site;
private String page;
public void setSite(String site) {
this.site = site;
}
public void setPage(String page) {
this.page = page;
}
@Override
public void doTag() throws JspException, IOException {
PageContext pc=(PageContext) this.getJspContext();
HttpServletRequest request=(HttpServletRequest)pc.getRequest();
HttpServletResponse response=(HttpServletResponse)pc.getResponse();
String referer=request.getHeader("referer");
if(referer==null||!referer.startsWith(site)){
if(page.startsWith(request.getContextPath())){
response.sendRedirect(page);
return;
}else if(page.startsWith("/")){
response.sendRedirect(request.getContextPath()+page);
}else{
response.sendRedirect(request.getContextPath()+"/"+page);
}
throw new SkipPageException();
}
else{
}
super.doTag();
}
*如何实现开发标签?
标签处理类如下:
/**
* 需求:开发<c:if>标签
* @author 芷若初荨
*
*/
public class IfElseTag extends SimpleTagSupport{
private boolean test;
public void setTest(boolean test){
this.test=test;
}
@Override
public void doTag() throws JspException, IOException {
if(test){
this.getJspBody().invoke(null);
}
}
*如何实现开发标签?
开发这个标签需要设置三个标签处理器,分别是父标签Choose标签处理器和两个子标签When标签处理器和otherwise标签处理器,这三个需要配合使用,如下:
**父标签choose处理器
/**
* 创建choose标签的处理器
* @author 芷若初荨
*
*/
public class ChooseTag extends SimpleTagSupport{
private boolean isDo;
public boolean isDo() {
return isDo;
}
public void setDo(boolean isDo) {
this.isDo = isDo;
}
@Override
public void doTag() throws JspException, IOException {
this.getJspBody().invoke(null);
}
}
**when标签处理器
/**
* 创建when标签的处理器
* @author 芷若初荨
*
*/
public class WhenTag extends SimpleTagSupport{
private boolean test;
public void setTest(boolean test) {
this.test = test;
}
@Override
public void doTag() throws JspException, IOException {
ChooseTag parent=(ChooseTag) this.getParent();
if(test&&!parent.isDo()){
this.getJspBody().invoke(null);
}else{}
}
}
**otherwise标签处理器
/**
* 开发otherwise标签,是when的兄弟标签
* @author 芷若初荨
*
*/
public class OtherWiseTag extends SimpleTagSupport{
@Override
public void doTag() throws JspException, IOException {
ChooseTag parent=(ChooseTag) this.getParent();
if(!parent.isDo()){
this.getJspBody().invoke(null);
parent.setDo(true);
}
}
}
*如何开发迭代标签?(foreach)
实例:
public class Foreach extends SimpleTagSupport{
private String var;
private Object items;
private Collection<Object> collection;
public void setVar(String var){
this.var=var;
}
public void setItems(Object items) {
this.items=items;
}
public void setCollection(Object items){
if(items instanceof Collection(Object items)){
this.collection=(Object)items;
}
if(items instanceof Map){
Map map=new Map();
this.collection=map.entrySet();
}
if(items.getClass().isArray()){
this.colletcion=new ArrayList();
int length=Array.getLength(items);
for(int i=0;i<length;i++){
Object object=Array.get(items,i);
this.collection.add(object);
}
}
}
public void doTag() throws JSPException{
this.setColletion(items);
Iterator<Object> iterator=collection.iterator();
while(iterator.hasNext()){
Object value=iterator.next();/
getJspContext().setAttribute(var,value);
getJSPBody().invoke(null);
}
}
}
//.tld文件描述标签
<?xml version="1.0" encoding="UTF-8"?>
<taglib>
<tlib-version>1.0</tlib-version>
<jsp-version>2.0</jsp-version>
<short-name>mine</short-name>
<uri>http://myTags.com/myTags</uri>
<tag>
<description>测试</description>
<name>out</name>
<tag-class>com.abc.FirstST</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>test</name>
<requird>true</requird>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
<tag>
<description>Foreach遍历输出</description>
<name>foreach</name>
<tag-class>com.abc.ForeachTag</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>var</name>
<requird>true</requird>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute> <name>items</name>
<requird>true</requird>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
</taglib>
在JSP中编写测试效果
<%@ taglib prefix="myTags" tagdir="/WEB-INF/tags"%>
<%@ taglib prefix="mine" uri="/WEB-INF/tags/myTags.tld" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
<title>测试自定义标签</title>
</head>
<body>
<% Integer num[] = {1,2,3};
request.setAttribute("num", num);%>
<% Map map = new LinkedHashMap();
map.put("a", "aaa");
map.put("b","bbb");
map.put("c", "ccc");
request.setAttribute("map", map);
%>
<br>---------自定义标签mine:foreach迭代效果---------<br>
<mine:foreach var="object" items="${num}">
${object}
</mine:foreach>
<mine:foreach var="object" items="${map}">
${object}
</mine:foreach>
<br>---------标准标签c:foreach迭代效果---------<br>
<c:forEach var="object" items="${num}">
${object}
</c:forEach>
<c:forEach var="object" items="${map}">
${object}
</c:forEach>
</body>
</html>
*如何实现HTML转义标签?(<)
标签处理类如下:
/**
* 需求:开发HTML的转义标签
* @author 芷若初荨
*
*/
public class HTMLFilterTag extends SimpleTagSupport{
@Override
public void doTag() throws JspException, IOException {
JspFragment jf=this.getJspBody();
StringWriter writer=new StringWriter();
jf.invoke(writer);
String content=writer.getBuffer().toString();
content=filter(content);
this.getJspContext().getOut().write(content);
}
public String filter(String message){
if(message==null){
return(null);
}
char content[]=new char[(message.length())];
message.getChars(0, message.length(), content,0);
StringBuffer result=new StringBuffer(content.length+50);
for(int i=0;i<content.length;i++){
switch(content[i]){
case '<':
result.append("<");
break;
default:
break;
}
}
return message;
}
}
*如何打包自己的标签库?