JSP自定义标签

一、为什么需要自定义标签
    1)与JSP页面整体统一
    2)还具有一定的业务逻辑功能,例如:循环、判断等

二、自定标签开发步骤
    一】第一步:写一个自定义的标签处理类

    public class Demo implements SimpleTag{

            private PageContext pageContext;

            //PageContext是JspContext的子类

            @Override

            public void setJspContext(JspContext jspContext) {

                System.out.println("Do setJspContext");

                //得到jsp页面对象

                pageContext = (PageContext) jspContext;

            }



            @Override

            public void doTag() throws JspException, IOException {

                System.out.println("Do doTag");

                //取得HttpServletRequest对象

                HttpServletRequest request= (HttpServletRequest) pageContext.getRequest();

                //得到ip地址

                String ip = request.getRemoteAddr();

                System.out.println(ip);

                //取得out <---> JspWriter对象

                JspWriter out = pageContext.getOut();

                //向浏览器输出IP地址信息

                out.write("<font size='30px' color='red'>" + "ip:" + ip + "</font>");

            }



            @Override

            public JspTag getParent() {

                return null;

            }



            @Override

            public void setJspBody(JspFragment arg0) {  

            }





            @Override

            public void setParent(JspTag arg0) {

            }

        }

 



    二】第二步:在/WEB-INF/目录下,写一个.tld文件,目的是让web容器知道自定义标签和标签处理类的对应关系

       <?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">

            

          <description>JSTL 1.1 core library</description>

          <display-name>JSTL core</display-name>

          <tlib-version>1.1</tlib-version>

          <short-name>sky</short-name>

          <uri>http://com.suse/jsp/jstl/sky</uri>

          

          <tag>

            <name>ip</name>

            <tag-class>com.suse.simpletag.Demo</tag-class>

            <body-content>empty</body-content> <!--empty:此标签为空标签-->

          </tag>

        </taglib>

 

 



    三】第三步:在JSP页面中,通过<%@taglib%>指令引用标签库

      <%@ taglib prefix="sky" uri="http://com.suse/jsp/jstl/sky"%>



        <sky:ip />

 

 



三、标签处理过程
    1)SimpleTag接口中有5个方法,这5个方法容器会在适当的时候选择调用,
    2)其中,doTag()方法最为核心,该方法中封装了该标签的处理业务逻辑
    3)项目中通常都会使用SimpleTagSupport类,该类已经对SimpleTag接口实现

四、案例:
    一】控制标签中的内容是否执行( <sky:execute>标签 )
        1)执行标签体     :调用invoke(null)方法
        2)不执行标签体   :不调用invoke(null)方法

    code:

            public class ExecuteTag extends SimpleTagSupport {

                @Override

                public void doTag() throws JspException, IOException {

                    //将此标签内的内容封装成JspFragment对象

                    JspFragment jspFragment = this.getJspBody();

                    //将标签中的内容进行输出,null表示默认输出到浏览器中,否则会输出到相应的流中

                    jspFragment.invoke(null); //若没有这条语句,那么此标签的内容便不会输出到浏览器页面中

                }

            }

        tag:

             <tag>

                  <name>execute</name>

                  <tag-class>com.suse.simpletag.ExecuteTag</tag-class>

                  <body-content>scriptless</body-content>       <!-- //scriptless表示不允许有脚本存在此标签内部 -->

             </tag>

 

 


    二】控制标签后的内容是否执行
        方法:抛出 SkipPageException 异常。导致标签体后的内容不执行

    code:

            public class SkipTag extends SimpleTagSupport {

                @Override

                public void doTag() throws JspException, IOException {

                    JspFragment jspFragment = this.getJspBody();

                    jspFragment.invoke(null);                    //设置此标签后的内容不再执行。方法:抛出一个 SkipPageException() 异常。

                    throw new SkipPageException();

                }

            }

      tag:

              <tag>

                  <name>skip</name>

                  <tag-class>com.suse.simpletag.SkipTag</tag-class>

                  <body-content>scriptless</body-content>

              </tag>

 

 




    三】将标签体中内容转换成大写

    public class UpperTag extends SimpleTagSupport {

        @Override

        public void doTag() throws JspException, IOException {

            JspFragment jspFragment = this.getJspBody();

            

            //创建一个缓冲区,用于存储标签中的内容

            StringWriter writer = new StringWriter();

            jspFragment.invoke(writer);

            

            //将缓冲区中的内容进行处理(小写 --> 大写)

            StringBuffer buffer = writer.getBuffer();

            String upString = buffer.toString().toUpperCase();

            

            //将转换后的内容输出到浏览器中

            JspContext jspContext = this.getJspContext();

            JspWriter out = jspContext.getOut();

            out.write(upString);

        }

 

 



    四】开发带属性的标签:
        1)在标签处理器中编写每个属性对应的setter方法
        2)在TLD文件中描述标签属性

   code:

        public class ForSkip extends SimpleTagSupport{

            private String var;

            private int begin;

            private int end;

            private int step = 1; //增量默认为1

            

            public void setVar(String var) {

                this.var = var;

            }

            public void setBegin(int begin) {

                this.begin = begin;

            }

            public void setEnd(int end) {

                this.end = end;

            }

            public void setStep(int step) {

                this.step = step;

            }

            

            @Override

            public void doTag() throws JspException, IOException {

                for (int i = this.begin; i <= this.end; i += this.step ) {

                    this.getJspContext().setAttribute(this.var, i);

                    this.getJspBody().invoke(null);

                }

            }

        }



    tld:

        <tag>

             <name>forskip</name>

             <tag-class>com.suse.simpletag.ForSkip</tag-class>

             <body-content>scriptless</body-content>

             <attribute>

                 <name>var</name>

                 <required>true</required>

                 <rtexprvalue>true</rtexprvalue>

             </attribute>

             <attribute>

                 <name>begin</name>

                 <required>true</required>

                 <rtexprvalue>true</rtexprvalue>

             </attribute>

             <attribute>

                 <name>end</name>

                 <required>true</required>

                 <rtexprvalue>true</rtexprvalue>

             </attribute>

             <attribute>

                 <name>step</name>

                 <required>false</required>

                 <rtexprvalue>true</rtexprvalue>

             </attribute>

        </tag>

    jsp:

        <sky:forskip var="item" begin="1" end="25" step="3">

            ${item} &nbsp;&nbsp;&nbsp;

        </sky:forskip>

 

 



    五】开发带有父标签的自定义标签
        思路:当某些标签是排它执行,此时:
          1) 可以在这些标签外,嵌入一个父标签,
          2) 并在父标签中做一个标志位,判断是否执行过。

  code:

        //1, <sky:choose> content </sky:choose>

        public class ChooseTag extends SimpleTagSupport {

            private boolean done = false;



            public boolean isDone() {

                return done;

            }

            

            public void setDone(boolean done) {

                this.done = done;

            }





            @Override

            public void doTag() throws JspException, IOException {

                JspFragment jspFragment =  this.getJspBody();

                jspFragment.invoke(null);

            }

            

        }



        //2,<sky:while test="${expr}"> content </sky:while>

        public class WhileTag extends SimpleTagSupport {

            

            private boolean test;

            public void setTest(boolean test) {

                this.test = test;

            }



            

            @Override

            public void doTag() throws JspException, IOException {

                //得到父标签后获取是否已经做过了

                ChooseTag chooseTag = (ChooseTag) this.getParent();

                boolean done = chooseTag.isDone();

                

                //如果没有做过,并且表达式成立

                if (!done && test) {

                    this.getJspBody().invoke(null);

                    chooseTag.setDone(true);

                }

            }

        }



        //3,<sky:otherwise>content</sky:otherwise>

        public class OtherWiseTag extends SimpleTagSupport {

            @Override

            public void doTag() throws JspException, IOException {

                //得到父类标签对象,获取到Done的状态,进行相应的处理

                ChooseTag chooseTag = (ChooseTag) this.getParent();

                boolean done = chooseTag.isDone();

                if (!done) {

                    this.getJspBody().invoke(null);

                    chooseTag.setDone(true);

                }

            }

        }



    tld:

         <tag>

             <name>choose</name>

             <tag-class>com.suse.simpletag.ChooseTag</tag-class>

             <body-content>scriptless</body-content>

         </tag>

         <tag>

             <name>while</name>

             <tag-class>com.suse.simpletag.WhileTag</tag-class>

             <body-content>scriptless</body-content>

             <attribute>

                 <name>test</name>

                 <required>true</required>

                 <rtexprvalue>true</rtexprvalue>

             </attribute>

         </tag>

        

         <tag>

             <name>otherwise</name>

             <tag-class>com.suse.simpletag.OtherWiseTag</tag-class>

             <body-content>scriptless</body-content>

         </tag>

    jsp:

        <%

        pageContext.setAttribute("age", 25);

        %>

        <sky:choose>

            <sky:while test="${age > 16}">

                你成年了<br />

            </sky:while>

            <sky:otherwise>

                你未成年 <br />

            </sky:otherwise>

        </sky:choose>

 

 



    六】防盗链

  code:

         public class Reference extends SimpleTagSupport{

            private String url;

            private String error;

            

            public void setUrl(String url) {

                this.url = url;

            }

            public void setError(String error) {

                this.error = error;

            }





            @Override

            public void doTag() throws JspException, IOException {

                //得到页面内置对象

                PageContext pageContext = (PageContext) this.getJspContext();

                HttpServletRequest request = (HttpServletRequest) pageContext.getRequest();

                HttpServletResponse response = (HttpServletResponse) pageContext.getResponse();

                

                //获取标签体中的内容并进行处理

                JspFragment jspFragment = this.getJspBody();

                String refer = request.getHeader("referer");

                System.out.println(refer);

                if (this.url.equals(refer)) { //referer头表明来自于哪里

                    jspFragment.invoke(null);

                } else {

                    try {

                        request.getRequestDispatcher(this.error).forward(request, response);

                    } catch (ServletException e) {

                        e.printStackTrace();

                    }

                }

                

            }

        }



    tld:

       <tag>

               <name>refer</name>

             <tag-class>com.suse.simpletag.Reference</tag-class>

             <body-content>scriptless</body-content>

             <attribute>

                 <name>url</name>

                 <required>true</required>

                 <rtexprvalue>true</rtexprvalue>

             </attribute>

             <attribute>

                 <name>error</name>

                 <required>true</required>

                 <rtexprvalue>true</rtexprvalue>

             </attribute>

         </tag>

    jsp:

        <sky:refer error="/ad.jsp" url="http://localhost:8080/day_16/index.jsp">

        <a href="#">下载</a>

        </sky:refer>

 

 



   七】仿写forEach自定义标签

   code:

        //Foreach自定义标签

        //Connection类族:  <sky:forEach var="item" items="${list}">${item}</sky:forEach>   <sky:forEach var="item" items="${set}">${item}</sky:forEach>

        //Map类族:<sky:forEach var="en" items="map">${en.key} ----- ${en.value}</sky:forEach>



        public class ForEachTag extends SimpleTagSupport {

            

            /*用一个Collection类来进行转换*/

            private Collection coll;

            

            private Object items;

            private String var;

            public void setItems(Object items) {

                /*设置coll的值:当为Collection类族时直接转换,否则保存Set<Entry<K,V>>形式的Connection*/

                if (items instanceof Collection) {

                    coll = (Collection) items;

                } else if(items instanceof Map) {

                    Map map = (Map) items;

                    coll = map.entrySet();

                }

            }

            public void setVar(String var) {

                this.var = var;

            }

            

            

            @Override

            public void doTag() throws JspException, IOException {

                for (Iterator it = coll.iterator(); it.hasNext(); ) {

                    //得到单个对象

                    Object obj = (Object) it.next();

                    

                    //将单个对象放入域对象中

                    PageContext pageContext = (PageContext) this.getJspContext();

                    pageContext.getRequest().setAttribute(this.var, obj);

                    

                    //将标签封装的表达式输出到页面中

                    this.getJspBody().invoke(null);

                }

            }

      







      tld:

         <tag>

             <name>forEach</name>

             <tag-class>com.suse.simpletag.ForEachTag</tag-class>

             <body-content>scriptless</body-content>

             <attribute>

                 <name>var</name>

                 <required>true</required>

                 <rtexprvalue>true</rtexprvalue>

             </attribute>

             <attribute>

                 <name>items</name>

                 <required>true</required>

                 <rtexprvalue>true</rtexprvalue>

             </attribute>

         </tag>



      jsp:

              <%

                List<String> list = new ArrayList<String>();

                list.add("jack");

                list.add("merry");

                list.add("berry");

                list.add("sky");

                

                pageContext.setAttribute("LIST", list);

                

                Map<String, String> map = new HashMap<String, String>();

                map.put("id", "121010");

                map.put("username", "jack");

                map.put("age", "15");

                

                pageContext.setAttribute("MAP", map);

            %>

            <sky:forEach items="${LIST}" var="item">

                ${item} &nbsp;&nbsp;

            </sky:forEach>

            <br />

            <sky:forEach items="${MAP}" var="en">

                ${en.key}:${en.value} <br />

            </sky:forEach>

 

 




    八】过滤器(防止恶意JS代码)

  code:

        //<simple:filter>标签处理类

        public class FilterTag extends SimpleTagSupport {

            public void doTag() throws JspException, IOException {

                JspFragment jspFragment = this.getJspBody();

                StringWriter writer = new StringWriter();

                jspFragment.invoke(writer);

                String temp = writer.getBuffer().toString();

                //结果必定是转义后的字符串

                temp = filter(temp);

                PageContext pageContext = (PageContext) this.getJspContext();

                pageContext.getOut().write(temp);

            }

            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("&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());

            }

        }

 

 



你可能感兴趣的:(jsp自定义标签)