JSP第七篇【自定义标签就是如此简单】(修订版)

 
 

前言

只有光头才能变强。

文本已收录至我的GitHub仓库,欢迎Star:https://github.com/ZhongFuCheng3y/3y

为什么要用到简单标签?

上一篇博客中我已经讲解了传统标签,想要开发自定义标签,大多数情况下都要重写doStartTag(),doAfterBody()和doEndTag()方法,并且还要知道SKIP_BODY,EVAL_BODY等等的变量代表着什么,在什么方法中使用。这样实在是太麻烦了!

因此,为了简化标签开发的复杂度,在JSP 2.0中定义了一个更为简单、便于编写和调用的SimpleTag接口来实现标签的功能。

一般来说,实现了SimpeTag接口的标签称之为简单标签

SimpleTag接口

public interface SimpleTag extends JspTag {    void doTag() throws JspException, IOException;    void setParent(JspTag var1);    JspTag getParent();    void setJspContext(JspContext var1);    void setJspBody(JspFragment var1);}interface SimpleTag extends JspTag {
    void doTag() throws JspException, IOException;

    void setParent(JspTag var1);

    JspTag getParent();

    void setJspContext(JspContext var1);

    void setJspBody(JspFragment var1);
}
void doTag() throws JspException, IOException;void setJspContext(JspContext var1);void setJspBody(JspFragment var1);

void setJspContext(JspContext var1);

void setJspBody(JspFragment var1);

快速入门

public class Demo1 extends SimpleTagSupport {    String format = null;    @Override    public void doTag() throws JspException, IOException {        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);        this.getJspContext().getOut().write(simpleDateFormat.format(new Date()));    }    public String getFormat() {        return format;    }    public void setFormat(String format) {        this.format = format;    }}class Demo1 extends SimpleTagSupport {


    String format = null;

    @Override
    public void doTag() throws JspException, IOException {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);

        this.getJspContext().getOut().write(simpleDateFormat.format(new Date()));
    }

    public String getFormat() {
        return format;
    }

    public void setFormat(String format) {
        this.format = format;
    }
}
<tag>    <name>formatDate</name>    <tag-class>tag.Demo1</tag-class>    <body-content>tagdependent</body-content>    <attribute>        <name>format</name>        <required>true</required>        <rtexprvalue>true</rtexprvalue>    </attribute></tag>
    <name>formatDate</name>
    <tag-class>tag.Demo1</tag-class>
    <body-content>tagdependent</body-content>
    <attribute>
        <name>format</name>
        <required>true</required>
        <rtexprvalue>true</rtexprvalue>
    </attribute>
</tag>
640?wx_fmt=png
640?wx_fmt=png

SimpleTagSupport类的执行顺序:

640?wx_fmt=png

深入简单标签

在我们讲解传统标签的时候,配合着SKIP_BODY、SKIP_PAGE等变量可以实现如下的功能:

  1. 控制jsp页面某一部分内容(标签体)是否执行

  2. 控制整个jsp页面是否执行

  3. 控制jsp页面内容重复执行

  4. 修改jsp页面内容输出


throw new SkipPageException();new SkipPageException();
640?wx_fmt=png

带标签体的简单标签

public abstract class JspFragment {    public JspFragment() {    }    public abstract void invoke(Writer var1) throws JspException, IOException;    public abstract JspContext getJspContext();}abstract class JspFragment {
    public JspFragment() {
    }

    public abstract void invoke(Writer var1) throws JspException, IOException;

    public abstract JspContext getJspContext();
}

JspFragment对象十分简单,重要的只有invoke(Writer var1)方法(获取JspContext对象并不重要,在标签描述器上就可以获取到了)

public abstract void invoke(java.io.Writer out) :


public class Demo1 extends SimpleTagSupport {    @Override    public void doTag() throws JspException, IOException {        //得到代表标签体的对象        JspFragment jspFragment = getJspBody();        //invoke方法接收的是一个Writer,如果为null,就代表着JspWriter(),将标签体的数据写给浏览器!        jspFragment.invoke(null);    }}class Demo1 extends SimpleTagSupport {
    @Override
    public void doTag() throws JspException, IOException {

        //得到代表标签体的对象
        JspFragment jspFragment = getJspBody();

        //invoke方法接收的是一个Writer,如果为null,就代表着JspWriter(),将标签体的数据写给浏览器!
        jspFragment.invoke(null);

    }
}
640?wx_fmt=png
public void doTag() throws JspException, IOException {    //得到代表标签体的对象    JspFragment jspFragment = getJspBody();    //jspFragment.invoke(null);}

    //得到代表标签体的对象
    JspFragment jspFragment = getJspBody();

    //jspFragment.invoke(null);

}
public void doTag() throws JspException, IOException {    //得到代表标签体的对象    JspFragment jspFragment = getJspBody();    jspFragment.invoke(null);    jspFragment.invoke(null);}

    //得到代表标签体的对象
    JspFragment jspFragment = getJspBody();

    jspFragment.invoke(null);
    jspFragment.invoke(null);

}
//得到代表标签体的对象JspFragment jspFragment = getJspBody();//创建可以存储字符串的Writer对象StringWriter stringWriter = new StringWriter();//invoke()方法把标签体的数据都写给流对象中jspFragment.invoke(stringWriter);//把流对象的数据取出来,流对象的数据就是标签体的内容String value = stringWriter.toString();//将数据改成是大写的,写到浏览器中getJspContext().getOut().write(value.toUpperCase());
JspFragment jspFragment = getJspBody();

//创建可以存储字符串的Writer对象
StringWriter stringWriter = new StringWriter();

//invoke()方法把标签体的数据都写给流对象中
jspFragment.invoke(stringWriter);

//把流对象的数据取出来,流对象的数据就是标签体的内容
String value = stringWriter.toString();

//将数据改成是大写的,写到浏览器中
getJspContext().getOut().write(value.toUpperCase());
640?wx_fmt=png

我们可以发现,传统标签能完成的功能,简单标签都可以完成,并且更为简单!


自定义标签的应用

既然我们学了简单标签,我们就用简单标签来做开发吧!

防盗链

在讲解request对象的时候,我们讲解过怎么实现防盗链的功能。现在我们使用标签来进行防盗链

模拟下场景:1.jsp页面是海贼王资源,2.jsp页面提示非法盗链,index1.jsp是我的首页。别人想要看我的海贼王资源,就必须通过我的首页点进去看,否则就是非法盗链!

@Overridepublic void doTag() throws JspException, IOException {    //如果想要做成更加灵活的,就把站点设置和资源设置成标签属性传递进来!    //等会我们要获取得到request对象,需要使用到JspContext的子类PageContext    PageContext pageContext = (PageContext) this.getJspContext();    //获取request对象    HttpServletRequest httpServletRequest = (HttpServletRequest) pageContext.getRequest();    //获取到referer    String referer = httpServletRequest.getHeader("Referer");    //获取到response对象,等会如果是非法盗链,就重定向别的页面上    HttpServletResponse httpServletResponse = (HttpServletResponse) pageContext.getResponse();    //非法盗链!    if (referer == null || !referer.startsWith("http://localhost:8080/zhongfucheng")) {        //2.jsp提示了非法盗链!        httpServletResponse.sendRedirect("/zhongfucheng/2.jsp");        //不执行页面下面的内容了,保护页面        throw new SkipPageException();    }}
public void doTag() throws JspException, IOException {

    //如果想要做成更加灵活的,就把站点设置和资源设置成标签属性传递进来!

    //等会我们要获取得到request对象,需要使用到JspContext的子类PageContext
    PageContext pageContext = (PageContext) this.getJspContext();

    //获取request对象
    HttpServletRequest httpServletRequest = (HttpServletRequest) pageContext.getRequest();

    //获取到referer
    String referer = httpServletRequest.getHeader("Referer");

    //获取到response对象,等会如果是非法盗链,就重定向别的页面上
    HttpServletResponse httpServletResponse = (HttpServletResponse) pageContext.getResponse();

    //非法盗链!
    if (referer == null || !referer.startsWith("http://localhost:8080/zhongfucheng")) {

        //2.jsp提示了非法盗链!
        httpServletResponse.sendRedirect("/zhongfucheng/2.jsp");

        //不执行页面下面的内容了,保护页面
        throw new SkipPageException();
    }
}
<zhongfucheng:Referer/><html><head>    <title></title></head><body>海贼王最新资源</body></html>
<html>
<head>
    <title></title>
</head>
<body>

海贼王最新资源

</body>
</html>
<h1>这是首页!</h1><a href="${pageContext.request.contextPath}/1.jsp"> 海贼王最新资源</a></h1>
<a href="${pageContext.request.contextPath}/1.jsp"> 海贼王最新资源</a>
<body>你是非法盗链的!!!!!!</body>
你是非法盗链的!!!!!!
</body>
640?wx_fmt=gif

if标签

在JSTL中,我们已经使用过了<c:if/>标签了,现在我们学习了自定义标签,可以开发类似于JSTL的if标签了!

既然是if标签,那么就需要编写带属性和带标签体的标签(需要判断是true还是false呀!,通过判断是否为真值来决定是否执行标签体的内容)

public class Demo1 extends SimpleTagSupport {    //定义一个Boolean类型的变量    boolean test ;    @Override    public void doTag() throws JspException, IOException {        //获取到代表标签体内容的对象        JspFragment jspFragment = this.getJspBody();        //如果为真值才执行标签体的内容        if (test == true) {            jspFragment.invoke(null);        }    }    public boolean isTest() {        return test;    }    public void setTest(boolean test) {        this.test = test;    }}class Demo1 extends SimpleTagSupport {

    //定义一个Boolean类型的变量
    boolean test ;

    @Override
    public void doTag() throws JspException, IOException {

        //获取到代表标签体内容的对象
        JspFragment jspFragment = this.getJspBody();

        //如果为真值才执行标签体的内容
        if (test == true) {
            jspFragment.invoke(null);
        }
    }

    public boolean isTest() {
        return test;
    }

    public void setTest(boolean test) {
        this.test = test;
    }
}
<tag>    <name>if</name>    <tag-class> tag.Demo1</tag-class>    <body-content>scriptless</body-content>    <attribute>        <name>test</name>        <required>true</required>        <rtexprvalue>true</rtexprvalue>    </attribute></tag>if</name>
    <tag-classtag.Demo1</tag-class>
    <body-content>scriptless</body-content>
    <attribute>
        <name>test</name>
        <required>true</required>
        <rtexprvalue>true</rtexprvalue>
    </attribute>
</tag>
640?wx_fmt=png
640?wx_fmt=png

forEach标签

forEach标签最基本的功能:遍历集合、数组

public class Demo2 extends SimpleTagSupport {    //遍历的是List集合,于是标签的属性就为List    private List items;    //遍历出来的对象就用Object存着,因为我们不知道List集合保存的是什么元素    private Object var;    @Override    public void doTag() throws JspException, IOException {        //获取到迭代器        Iterator iterator = items.iterator();        //遍历集合        while (iterator.hasNext()) {            //获取到集合的元素            var = iterator.next();            //.....var属性代表的就是集合的元素,现在问题来了,好像在标签体内无法获取到这个对象....            //做到这里完成不下去了....        }    }    public void setItems(List items) {        this.items = items;    }    public void setVar(Object var) {        this.var = var;    }}class Demo2 extends SimpleTagSupport {

    //遍历的是List集合,于是标签的属性就为List
    private List items;

    //遍历出来的对象就用Object存着,因为我们不知道List集合保存的是什么元素
    private Object var;


    @Override
    public void doTag() throws JspException, IOException {

        //获取到迭代器
        Iterator iterator = items.iterator();

        //遍历集合
        while (iterator.hasNext()) {

            //获取到集合的元素
            var = iterator.next();

            //.....var属性代表的就是集合的元素,现在问题来了,好像在标签体内无法获取到这个对象....
            //做到这里完成不下去了....
        }
    }

    public void setItems(List items) {
        this.items = items;
    }

    public void setVar(Object var) {
        this.var = var;
    }
}

上面的思路是正常的,但是做不下去!我们换一个思路呗。上面的问题主要是在标签体获取不到被遍历出来的对象

我们这样做:把var定义成String类型的,如果遍历得到对象了,就设置PageContext的属性,var为关键字,对象为值。在标签体用EL表达式搜索以var为关键字的对象!每遍历出一个对象,就执行一次标签体!

public class Demo1 extends SimpleTagSupport {    //遍历的是List集合,定义List集合成员变量    private List items;    //以var为关键字存储到PageContext    private String var;    @Override    public void doTag() throws JspException, IOException {        //获取到集合的迭代器        Iterator iterator = items.iterator();        //获取到代表标签体内容的对象        JspFragment jspFragment = this.getJspBody();        //遍历集合        while (iterator.hasNext()) {            Object o = iterator.next();            //把遍历出来的对象存储到page范围中,关键字为标签的属性var(在标签体中使用EL表达式${var},就能够获取到集合的对象了!)            this.getJspContext().setAttribute(var, o);            //每设置了一个属性,我就执行标签体            jspFragment.invoke(null);        }    }    public void setItems(List items) {        this.items = items;    }    public void setVar(String var) {        this.var = var;    }}class Demo1 extends SimpleTagSupport {

    //遍历的是List集合,定义List集合成员变量
    private List items;

    //以var为关键字存储到PageContext
    private String var;



    @Override
    public void doTag() throws JspException, IOException {

        //获取到集合的迭代器
        Iterator iterator = items.iterator();

        //获取到代表标签体内容的对象
        JspFragment jspFragment = this.getJspBody();

        //遍历集合
        while (iterator.hasNext()) {
            Object o = iterator.next();

            //把遍历出来的对象存储到page范围中,关键字为标签的属性var(在标签体中使用EL表达式${var},就能够获取到集合的对象了!)
            this.getJspContext().setAttribute(var, o);

            //每设置了一个属性,我就执行标签体
            jspFragment.invoke(null);
        }
    }

    public void setItems(List items) {
        this.items = items;
    }

    public void setVar(String var) {
        this.var = var;
    }
}
<tag>    <name>forEach</name>    <tag-class>tag.Demo1</tag-class>    <body-content>scriptless</body-content>    <attribute>        <name>var</name>        <rtexprvalue>true</rtexprvalue>        <!--字符串即可,不需要EL表达式的支持-->        <required>false</required>    </attribute>    <attribute>        <name>items</name>        <required>true</required>        <rtexprvalue>true</rtexprvalue>    </attribute></tag>
    <name>forEach</name>
    <tag-class>tag.Demo1</tag-class>
    <body-content>scriptless</body-content>
    <attribute>
        <name>var</name>
        <rtexprvalue>true</rtexprvalue>
        <!--字符串即可,不需要EL表达式的支持-->
        <required>false</required>
    </attribute>

    <attribute>
        <name>items</name>
        <required>true</required>
        <rtexprvalue>true</rtexprvalue>
    </attribute>
</tag>
<%    List list = new ArrayList();    list.add("zhongfucneng");    list.add("1");    list.add("2");    list.add("3");    request.setAttribute("list",list);%><zhongfucheng:forEach items="${list}" var="str">    ${str}</zhongfucheng:forEach>new ArrayList();
    list.add("zhongfucneng");
    list.add("1");
    list.add("2");
    list.add("3");

    request.setAttribute("list",list);
%>
<zhongfucheng:forEach items="${list}" var="str">

    ${str}

</zhongfucheng:forEach>
640?wx_fmt=png

上面写的仅仅能够遍历List集合,做一个通用的forEach标签麻烦的是在:不知道传进来的是什么类型的数组、什么类型集合!,需要逐一去判断

//如果items是Collection类型的,就强转为Colletionif (items instanceof Collection) {    collection = (Collection) items;}//如果itmes是Map类型的,那么就强转为Map,再获取到<Map.Entry<K, V>,这个是Set集合的!if (items instanceof Map) {    Map map = (Map) items;    collection = (Collection) map.entrySet();}//对象数组if (items instanceof Object[]) {    Object[] objects = (Object[]) items;    collection = Arrays.asList(objects);}//int[],Byte[],char[]等八大基本数据类型.....
if (items instanceof Collection) {
    collection = (Collection) items;
}

//如果itmes是Map类型的,那么就强转为Map,再获取到<Map.Entry<K, V>,这个是Set集合的!
if (items instanceof Map) {
    Map map = (Map) items;
    collection = (Collection) map.entrySet();
}

//对象数组
if (items instanceof Object[]) {
    Object[] objects = (Object[]) items;
    collection = Arrays.asList(objects);
}

//int[],Byte[],char[]等八大基本数据类型.....

还有int[],byte[],char[]等八大基本数据类型,这八大基本数据类型就不能用Arrays.asList()把引用传进去了。因为JDK5以后会把引用自动装箱成Interger[]、Byte[]等等,而不是获取到数组的元素数据。

public static void main(String[] args) {    int[] ints = new int[]{1, 2, 3};    Object[] objects = new Object[]{"1", "2", "3"};    if (objects instanceof Object[]) {        Collection collection = Arrays.asList(objects);        System.out.println(collection);    }    if (ints instanceof int[]) {        Collection collection1 = Arrays.asList(ints);        System.out.println(collection1);    }}

    int[] ints = new int[]{123};
    Object[] objects = new Object[]{"1""2""3"};

    if (objects instanceof Object[]) {
        Collection collection = Arrays.asList(objects);
        System.out.println(collection);
    }
    if (ints instanceof int[]) {

        Collection collection1 = Arrays.asList(ints);
        System.out.println(collection1);
    }
}
640?wx_fmt=png
if (items instanceof int[]) {    int[] ints = (int[]) items;    collection = new ArrayList();    for (int anInt : ints) {        collection.add(anInt);    }}//......这里还要写7个instanceof int[]) {
    int[] ints = (int[]) items;
    collection = new ArrayList();
    for (int anInt : ints) {
        collection.add(anInt);
    }

}
//......这里还要写7个
640?wx_fmt=png

由于JDK5的新特性,我们又有另外的解决方案,Class对象能够判断是否为数组类,reflect反射包下Array类

public class Demo1 extends SimpleTagSupport {    //遍历的是未知的集合或数组,定义成Object    private Object items;    //每次被遍历的对象存储关键字    private String var;    //Colletion    private Collection collection;    //在WEB容器设置标签的属性的时候,判断是什么类型的数组和集合    public void setItems(Object items) {        this.items = items;        //如果items是Collection类型的,就强转为Colletion        if (items instanceof Collection) {            collection = (Collection) items;        }        //如果itmes是Map类型的,那么就强转为Map,再获取到<Map.Entry<K, V>,这个是Set集合的!        if (items instanceof Map) {            Map map = (Map) items;            collection = (Collection) map.entrySet();        }        //可以这样解决,Class对象判断是否是一个数组类        if (items.getClass().isArray()) {            //创建Collection集合添加数组的元素!            collection = new ArrayList();            //再利用reflect包下的Array类获取到该数组类的长度            int len = Array.getLength(items);            //遍历并添加到集合中            for (int i = 0; i < len; i++) {                collection.add(Array.get(items, i));            }        }    }    public void setVar(String var) {        this.var = var;    }   @Override    public void doTag() throws JspException, IOException {        //获取到代表标签体内容的对象        JspFragment jspFragment = this.getJspBody();        Iterator iterator = collection.iterator();        //遍历集合        while (iterator.hasNext()) {            Object o = iterator.next();            //把遍历出来的对象存储到page范围中(在标签体中使用EL表达式${var},就能够获取到集合的对象了!)            this.getJspContext().setAttribute(var, o);            jspFragment.invoke(null);        }    }}class Demo1 extends SimpleTagSupport {

    //遍历的是未知的集合或数组,定义成Object
    private Object items;

    //每次被遍历的对象存储关键字
    private String var;

    //Colletion
    private Collection collection;

    //在WEB容器设置标签的属性的时候,判断是什么类型的数组和集合
    public void setItems(Object items) {
        this.items = items;

        //如果items是Collection类型的,就强转为Colletion
        if (items instanceof Collection) {
            collection = (Collection) items;
        }

        //如果itmes是Map类型的,那么就强转为Map,再获取到<Map.Entry<K, V>,这个是Set集合的!
        if (items instanceof Map) {
            Map map = (Map) items;
            collection = (Collection) map.entrySet();
        }

        //可以这样解决,Class对象判断是否是一个数组类
        if (items.getClass().isArray()) {

            //创建Collection集合添加数组的元素!
            collection = new ArrayList();

            //再利用reflect包下的Array类获取到该数组类的长度
            int len = Array.getLength(items);

            //遍历并添加到集合中
            for (int i = 0; i < len; i++) {
                collection.add(Array.get(items, i));
            }
        }
    }

    public void setVar(String var) {
        this.var = var;
    }

   @Override
    public void doTag() throws JspException, IOException {

        //获取到代表标签体内容的对象
        JspFragment jspFragment = this.getJspBody();
        Iterator iterator = collection.iterator();


        //遍历集合
        while (iterator.hasNext()) {
            Object o = iterator.next();

            //把遍历出来的对象存储到page范围中(在标签体中使用EL表达式${var},就能够获取到集合的对象了!)
            this.getJspContext().setAttribute(var, o);

            jspFragment.invoke(null);
        }
    }
}
<%    /*list集合*/    List list = new ArrayList();    list.add("zhongfucneng");    list.add("1");    list.add("2");    list.add("3");    request.setAttribute("list",list);    /*基本数据类型数组*/    int[] ints = new int[]{1, 2, 3, 4, 5};    request.setAttribute("ints", ints);    /*对象数组*/    Object[] objects = new Object[]{2, 3, 4, 5, 6};    request.setAttribute("objects", objects);    /*map集合*/    Map map = new HashMap();    map.put("aa", "aa");    map.put("bb", "bb");    map.put("cc", "cc");    request.setAttribute("map",map);%>    List集合:    <zhongfucheng:forEach items="${list}" var="str">        ${str}    </zhongfucheng:forEach>    <hr>    <hr>    基本数据类型数组:    <zhongfucheng:forEach items="${ints}" var="i">        ${i}    </zhongfucheng:forEach>    <hr>    <hr>    对象数组:    <zhongfucheng:forEach items="${objects}" var="o">        ${o}    </zhongfucheng:forEach>    <hr>    <hr>    map集合:    <zhongfucheng:forEach items="${map}" var="me">        ${me.key} = ${me.value}    </zhongfucheng:forEach>/*list集合*/
    List list = new ArrayList();
    list.add("zhongfucneng");
    list.add("1");
    list.add("2");
    list.add("3");
    request.setAttribute("list",list);

    /*基本数据类型数组*/
    int[] ints = new int[]{12345};
    request.setAttribute("ints", ints);

    /*对象数组*/
    Object[] objects = new Object[]{23456};
    request.setAttribute("objects", objects);

    /*map集合*/
    Map map = new HashMap();
    map.put("aa""aa");
    map.put("bb""bb");
    map.put("cc""cc");
    request.setAttribute("map",map);
%>

    List集合:
    <zhongfucheng:forEach items="${list}" var="str">
        ${str}
    </zhongfucheng:forEach>

    <hr>
    <hr>
    基本数据类型数组:
    <zhongfucheng:forEach items="${ints}" var="i">
        ${i}
    </zhongfucheng:forEach>

    <hr>
    <hr>
    对象数组:

    <zhongfucheng:forEach items="${objects}" var="o">
        ${o}
    </zhongfucheng:forEach>

    <hr>
    <hr>

    map集合:
    <zhongfucheng:forEach items="${map}" var="me">
        ${me.key} = ${me.value}
    </zhongfucheng:forEach>
640?wx_fmt=png

HTML转义标签

要开发这个标签就很简单了,只要获取到标签体的内容,再通过经过方法转义下标签体内容,输出给浏览器即可

public class Demo1 extends SimpleTagSupport {   @Override    public void doTag() throws JspException, IOException {       //获取到标签体的内容再修改       StringWriter stringWriter = new StringWriter();       JspFragment jspFragment = this.getJspBody();       jspFragment.invoke(stringWriter);       String content = stringWriter.toString();       //经过filter()转义,该方法在Tomcat可以找到       content = filter(content);       //再把转义后的内容输出给浏览器       this.getJspContext().getOut().write(content);    }    private 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("&lt;");                    break;                case '>':                    result.append("&gt;");                    break;                case '&':                    result.append("&amp;");                    break;                case '"':                    result.append("&quot;");                    break;                default:                    result.append(content[i]);            }        }        return (result.toString());    }}class Demo1 extends SimpleTagSupport {



   @Override
    public void doTag() throws JspException, IOException {

       //获取到标签体的内容再修改
       StringWriter stringWriter = new StringWriter();
       JspFragment jspFragment = this.getJspBody();
       jspFragment.invoke(stringWriter);
       String content = stringWriter.toString();

       //经过filter()转义,该方法在Tomcat可以找到
       content = filter(content);

       //再把转义后的内容输出给浏览器
       this.getJspContext().getOut().write(content);


    }

    private 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("&lt;");
                    break;
                case '>':
                    result.append("&gt;");
                    break;
                case '&':
                    result.append("&amp;");
                    break;
                case '"':
                    result.append("&quot;");
                    break;
                default:
                    result.append(content[i]);
            }
        }

        return (result.toString());
    }
}
<zhongfucheng:filter><a href="2.jsp">你好啊</a> </zhongfucheng:filter><br><a href="2.jsp">你好啊

<br>
<a href="2.jsp">你好啊
640?wx_fmt=png

if else标签

在JSTL中并没有if else的标签,JSTL给予我们的是choose,when,otherwise标签,现在我们模仿choose,when,otherwise开发标签

思路:when标签有个test属性,但otherwise怎么判断标签体是执行还是不执行呢?这时就需要choose标签的支持了!choose标签默认定义一个Boolean值为false,。当when标签体被执行了,就把Boolean值变成true,只要Boolean值为false就执行otherwise标签体的内容。

看程序就容易理解上面那句话了:

public class Choose extends SimpleTagSupport {    private boolean flag;    @Override    public void doTag() throws JspException, IOException {        this.getJspBody().invoke(null);    }    public boolean isFlag() {        return flag;    }    public void setFlag(boolean flag) {        this.flag = flag;    }}class Choose extends SimpleTagSupport {

    private boolean flag;

    @Override
    public void doTag() throws JspException, IOException {

        this.getJspBody().invoke(null);
    }

    public boolean isFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }
}
public class When extends SimpleTagSupport {    private boolean test ;    @Override    public void doTag() throws JspException, IOException {        Choose choose = (Choose) this.getParent();        //如果test为true和flag为false,那么执行该标签体        if (test == true && choose.isFlag() == false) {            this.getJspBody().invoke(null);            //修改父标签的flag            choose.setFlag(true);        }    }    public void setTest(boolean test) {        this.test = test;    }}class When extends SimpleTagSupport {

    private boolean test ;

    @Override
    public void doTag() throws JspException, IOException {


        Choose choose = (Choose) this.getParent();

        //如果test为true和flag为false,那么执行该标签体
        if (test == true && choose.isFlag() == false) {

            this.getJspBody().invoke(null);

            //修改父标签的flag
            choose.setFlag(true);
        }

    }
    public void setTest(boolean test) {
        this.test = test;
    }
}
public class OtherWise extends SimpleTagSupport {    @Override    public void doTag() throws JspException, IOException {        Choose choose = (Choose) this.getParent();        //如果父标签的flag为false,就执行标签体(如果when标签没执行,flag值就不会被修改!when标签没执行,就应该执行otherwise标签!)        if (choose.isFlag() == false) {            getJspBody().invoke(null);            //改父标签的flag为false            choose.setFlag(true);        }    }}class OtherWise extends SimpleTagSupport {


    @Override
    public void doTag() throws JspException, IOException {


        Choose choose = (Choose) this.getParent();

        //如果父标签的flag为false,就执行标签体(如果when标签没执行,flag值就不会被修改!when标签没执行,就应该执行otherwise标签!)
        if (choose.isFlag() == false) {
            getJspBody().invoke(null);

            //改父标签的flag为false
            choose.setFlag(true);

        }
    }
}
<zhongfucheng:choose>    <zhongfucheng:when test="${user!=null}">        user为空    </zhongfucheng:when>    <zhongfucheng:otherwise>        user不为空    </zhongfucheng:otherwise></zhongfucheng:choose>"${user!=null}">
        user为空
    </zhongfucheng:when>

    <zhongfucheng:otherwise>
        user不为空
    </zhongfucheng:otherwise>

</zhongfucheng:choose>
640?wx_fmt=png

DynamicAttribute接口

此接口的主要功能是用于完成动态属性的设置!前面我们讲解属性标签的时候,属性都是写多少个,用多少个的。现在如果我希望属性可以动态的增加,只需要在标签处理器类中实现DynamicAttribute接口即可!

现在我要开发一个动态加法的标签

public class Demo1 extends SimpleTagSupport implements DynamicAttributes {    //既然有动态属性和动态的值,那么我们就用一个Map集合存储(1-1对应的关系),做的加法运算,值为Double类型的。    Map<String, Double> map = new HashMap<>();    @Override    public void doTag() throws JspException, IOException {        //定义一个sum变量用于计算总值        double sum = 0.0;        //获取到Map集合的数据        Iterator iterator = map.entrySet().iterator();        while (iterator.hasNext()) {            Map.Entry<String, Double> entry = (Map.Entry<String, Double>) iterator.next();            sum += entry.getValue();        }        //向浏览器输出总和是多少        this.getJspContext().getOut().write(String.valueOf(sum));    }    //对于这个要实现的方法,我们只要关注第2个参数和第3个参数即可    //第二个参数表示的是动态属性的名称,第三个参数表示的是动态属性的值    @Override    public void setDynamicAttribute(String s, String localName, Object value) throws JspException {        //将动态属性的名字和值加到Map集合中        map.put(localName, Double.valueOf(Float.valueOf(value.toString())));    }}class Demo1 extends SimpleTagSupport implements DynamicAttributes {

    //既然有动态属性和动态的值,那么我们就用一个Map集合存储(1-1对应的关系),做的加法运算,值为Double类型的。
    Map<String, Double> map = new HashMap<>();

    @Override
    public void doTag() throws JspException, IOException {

        //定义一个sum变量用于计算总值
        double sum = 0.0;

        //获取到Map集合的数据
        Iterator iterator = map.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, Double> entry = (Map.Entry<String, Double>) iterator.next();

            sum += entry.getValue();
        }

        //向浏览器输出总和是多少
        this.getJspContext().getOut().write(String.valueOf(sum));
    }


    //对于这个要实现的方法,我们只要关注第2个参数和第3个参数即可
    //第二个参数表示的是动态属性的名称,第三个参数表示的是动态属性的值
    @Override
    public void setDynamicAttribute(String s, String localName, Object value) throws JspException {

        //将动态属性的名字和值加到Map集合中
        map.put(localName, Double.valueOf(Float.valueOf(value.toString())));
    }
}
<tag>    <name>dynamicAttribute</name>    <tag-class> tag.Demo1</tag-class>    <body-content> empty</body-content>    <!--这个必须要设置为true-->    <dynamic-attributes>true</dynamic-attributes></tag>
    <name>dynamicAttribute</name>
    <tag-class> tag.Demo1</tag-class>
    <body-content> empty</body-content>

    <!--这个必须要设置为true-->
    <dynamic-attributes>true</dynamic-attributes>
</tag>
<zhongfucheng:dynamicAttribute num="1.1" num2="2.2" num3="1"/>"2.2" num3="1"/>
640?wx_fmt=png

开发自定义函数

至于怎么开发自定义函数,在EL表达式的博客中有

最后

乐于输出干货的Java技术公众号:Java3y。公众号内有200多篇原创技术文章、海量视频资源、精美脑图,不妨来关注一下!

640?wx_fmt=jpeg

有帮助?好看!转发! 640


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值