15.自定义标签开发案例(我的JavaEE笔记)

主要内容:

  • 防盗链
  • 开发if标签
  • 开发if else标签
  • 开发foreach标签
  • 开发HTML转义的标签
  • 打包标签库

一、防盗链

防盗链的意思是,比如一个网站有一个资源很好,希望来访者先进入首页看完广告才能看到这个资源,如果不加防盗链,则别的网站可能加如此资源的超链接,那么就没有进入首页看广告。我们需要防止除从首页访问资源的其他方式。(工程tag_example
相关代码:
itcast.tld



    1.0
    itcast
    /itcast
    
    
        referer
        cn.itcast.web.tag.RefererTag
        empty
        
            site
            true
            true
        
        
            page
            true
            true
        
    

index.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>



  
    My JSP 'index.jsp' starting page
    
    
        
  
  
  
    内容链接
  

1.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="/itcast" prefix="itcast" %>




  
    保护页面
    
    
        
  
  
  
    This is my JSP page. 

RefererTag.java

package cn.itcast.web.tag;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.SkipPageException;
import javax.servlet.jsp.tagext.SimpleTagSupport;

public class RefererTag extends SimpleTagSupport {
    private String site ;
    private String page ;
    
    @Override
    public void doTag() throws JspException, IOException {
        //拿到来访者代表page的实例对象
        PageContext pageContext = (PageContext) this.getJspContext();
        HttpServletRequest request = (HttpServletRequest) pageContext.getRequest();
        String referer = request.getHeader("referer");
        
        //判断
        //如果地址为空或者地址不是我们给定的地址,就跳转到page页面
        if(referer == null || !referer.startsWith(site)){
            HttpServletResponse response = (HttpServletResponse) pageContext.getResponse();
            String webroot = request.getContextPath();//得到/day11_example
            //如果page="/day11_example/index.jsp"
            if(page.startsWith(webroot)){
                response.sendRedirect(page);
            }else {
                //如果page="/index.jsp"
                response.sendRedirect(webroot + page);
            }
            //重定向之后我们不能让保护页面显示,要让浏览器先进入index.jsp再进入保护页面
            throw new SkipPageException();
        }

    }

    public String getSite() {
        return site;
    }

    public void setSite(String site) {
        this.site = site;
    }

    public String getPage() {
        return page;
    }

    public void setPage(String page) {
        this.page = page;
    }
}

说明:

  • 1.我们在首页中给出资源页面(保护页面)的链接,在保护页面(1.jsp)中使用自定义标签进行检测:
    。如果资源不是从site指定的地址进入,则跳转到index.jsp页面。当然为了更好的匹配page,我们提供两种方式指定地址,一种是page="/index.jsp",一种是page="/tag_example/index.jsp"
  • 2.需要注意的是当我们处理外来地址访问之后需要抛出SkipPageException异常,不让后面的页面进行显示。

二、开发 if 标签

相关代码:
itcast.tld


    
        if
        cn.itcast.web.tag.IfTag
        scriptless
        
            test
            true
            true
        
    

2.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="/itcast" prefix="itcast" %>



  
    if标签
    
    
        
  
  
  
    
        xxxx
    
  

IfTag.java

package cn.itcast.web.tag;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
//开发if标签
public class IfTag extends SimpleTagSupport {
    
    private boolean test;

    @Override
    public void doTag() throws JspException, IOException {
        //只有在满足test条件的时候才执行
        if(test){
            this.getJspBody().invoke(null);
        }
    }

    public boolean isTest() {
        return test;
    }

    public void setTest(boolean test) {
        this.test = test;
    }
}

说明:当满足test为ture时才执行相关页面内容。

三、开发if else 标签

相关代码:
itcast.tld


    
        choose
        cn.itcast.web.tag.ChooseTag
        scriptless
    
    
        when
        cn.itcast.web.tag.WhenTag
        scriptless
        
            test
            true
            true
        
    
    
        otherwise
        cn.itcast.web.tag.OtherwiseTag
        scriptless
    

ChooseTag.java

package cn.itcast.web.tag;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class ChooseTag extends SimpleTagSupport {
    private boolean isOk;

    @Override
    public void doTag() throws JspException, IOException {
        this.getJspBody().invoke(null);
    }

    public boolean isOk() {
        return isOk;
    }

    public void setOk(boolean isOk) {
        this.isOk = isOk;
    }
}

WhenTag.java

package cn.itcast.web.tag;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class WhenTag extends SimpleTagSupport {
    private boolean test;

    @Override
    public void doTag() throws JspException, IOException {
        ChooseTag parent = (ChooseTag) this.getParent();
        if(test == true && parent.isOk() == false){
            this.getJspBody().invoke(null);
            parent.setOk(true);
        }
    }

    public boolean isTest() {
        return test;
    }
    public void setTest(boolean test) {
        this.test = test;
    }
}

OtherwiseTag.java

package cn.itcast.web.tag;
import java.io.IOException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class OtherwiseTag extends SimpleTagSupport {

    @Override
    public void doTag() throws JspException, IOException {
        ChooseTag parent = (ChooseTag) this.getParent();
        if(parent.isOk() == false){
            this.getJspBody().invoke(null);
            parent.setOk(true);
        }
    }
}

3.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="/itcast" prefix="itcast" %>



  
    if else标签
    
    
        
  
  
  
    
        aaa
        bbb
    
  

说明:开发if else标签需要三个标签组合起来。同时我们在父标签中设置了一个标志位,如果标志位为true表示已经执行了。默认是false。

四、开发迭代标签ForEach

相关代码:
itcast.tld


    
        foreach
        cn.itcast.web.tag.ForEachTag
        scriptless
        
            var
            true
            false
        
        
            items
            true
            true
        
    

ForEachTag.java

package cn.itcast.web.tag;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class ForEachTag extends SimpleTagSupport {

    private List items;
    private String var;

    @Override
    public void doTag() throws JspException, IOException {
        
        PageContext pageContext = (PageContext) this.getJspContext();
        
        Iterator it = items.iterator();
        while(it.hasNext()){
          //因为我们不知道集合中的内容是什么类型,所以一定要用Object类
            Object obj = it.next();
            //后一次的值会覆盖前一次的值,将得到的值存到pageContext域中
            pageContext.setAttribute(var, obj);
            this.getJspBody().invoke(null);
        }
    }
    public void setItems(List items) {
        this.items = items;
    }

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

4.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="/itcast" prefix="itcast" %>


  
    ForEach标签
    
    
        
  
  
  
    <%
        List list = new ArrayList();
        list.add("aa");
        list.add("bb");
        request.setAttribute("list", list);
     %>
     
        ${str }
     
     
  

说明:显然这个标签是不完善的,因为只能处理List集合,我们需要进行改进。
相关代码:(重点)
itcast.tld


        foreach2
        cn.itcast.web.tag.ForEachTag2
        scriptless
        
            var
            true
            false
        
        
            items
            true
            true
        

ForEachTag2.java

package cn.itcast.web.tag;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.lang.reflect.Array;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.SimpleTagSupport;

public class ForEachTag2 extends SimpleTagSupport {

    //不知道要迭代的类型使用Object代替
    private Object items;
    private String var;
    private Collection collection;

    @Override
    public void doTag() throws JspException, IOException {
        PageContext pageContext = (PageContext) this.getJspContext();
        Iterator it = collection.iterator();
        while(it.hasNext()){
            Object obj = it.next();
            pageContext.setAttribute(var, obj);
            this.getJspBody().invoke(null);
        }
    }

    public void setItems(Object items) {
        this.items = items;
        
        //如果传递进来的是一个集合
        if(items instanceof Collection){
            collection = (Collection) items;
        }
        
        //如果传递进来的是一个对象数组
        /*if(items instanceof Object[]){
            Object arg[] = (Object[]) items;
            collection = Arrays.asList(arg);
        }*/
        
        //如果传递进来的是一个Map
        if(items instanceof Map){
            Map map = (Map) items;
            collection = map.entrySet();
        }
        
        //如果传递进来的是一个基本数据类型数组
        /*if(items instanceof int[]){
            int temp[] = (int[]) items;
            collection = new ArrayList();
            for(int num : temp){
                collection.add(num);
            }
        }*///对于基本数据类型这样写八次很麻烦,sun公司的源码也是这样判断的。。。
        
        //对于数组类型(对象数组和基本数据数组)我们使用此种方式改进
        if(items.getClass().isArray()){
            collection = new ArrayList();
            int len = Array.getLength(items);
            for(int i = 0; i < len; i++){
                Object obj = Array.get(items, i);
                collection.add(obj);
            }
        }
    }

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

    public void setCollection(Collection collection) {
        this.collection = collection;
    }
}

5.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="/itcast" prefix="itcast" %>



  
    ForEach标签2
    
    
        
  
  
  
    <%
        List list = new ArrayList();
        list.add("aa");
        list.add("bb");
        request.setAttribute("list", list);
        
        Integer arr[] = new Integer[]{1,2,3};
        request.setAttribute("arr", arr);
        
        Map map = new HashMap();
        map.put("a", "aaa");
        map.put("b", "bbb");
        map.put("c", "ccc");
        request.setAttribute("map", map);
     %>
     
        ${str }
     
${num }
<% int arr1[] = new int[]{1,2,3}; request.setAttribute("arr1", arr1); byte[] arr2 = new byte[]{3,2,1}; request.setAttribute("arr2", arr2); %> ${num } ${num }

说明:

  • 1.首先我们分析一些可能会遇到的数据类型。数据类型有集合、Map、数组,数组中又分对象数组和基本数据类型数组。我们可以在execute方法中依次进行判断,但是会有很多重复代码,于是我们统一在setItems方法中进行判断。首先对于集合、Map、对象数组我们可以统统将其转换为Collection对象。单数对于基本数据类型数组的处理其实sun公司是进行了八次判断,显然较为麻烦。这里其实我们可以将数组统一处理,从代码中可以看到。
  • 2.判断过程。如果本来就是一个Collection对象,则直接转换。如果是对象数组,则先转换成Object对象,然后再转换成Collection对象。如果是Map对象,其实本身这个对象在迭代的时候也是通过Set集合进行迭代的,所以这里我们可以将其先转换成Collection对象。然后是八种基本数据类型的转换,但是之后我们对数组的处理进行了修改,我们这里统一处理。

五、开发HTML转义标签

相关代码:
itcast.tld


    
        htmlFilter
        cn.itcast.web.tag.HtmlFilterTag
        scriptless
    

HtmlFilterTag.java

package cn.itcast.web.tag;
import java.io.IOException;
import java.io.StringWriter;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;
//这个方法在源码中可以找到
public class HtmlFilterTag extends SimpleTagSupport {

    @Override
    public void doTag() throws JspException, IOException {
        StringWriter sw = new StringWriter();
        this.getJspBody().invoke(sw);
        
        //得到标签体
        String content = sw.getBuffer().toString();
        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);
        StringBuilder result = new StringBuilder(content.length + 50);
        for (int i = 0; i < content.length; i++) {
            switch (content[i]) {
            case '<':
                result.append("<");
                break;
            case '>':
                result.append(">");
                break;
            case '&':
                result.append("&");
                break;
            case '"':
                result.append(""");
                break;
            default:
                result.append(content[i]);
            }
        }
        return (result.toString());

    }
}

6.jsp


    
        链接
    
  

说明:这个标签中的方法filter其实我们可以在源码中找到,地址是apache-tomcat-8.0.26-src\webapps\examples\WEB-INF\classes\util\HTMLFilter.java。主要是为了在页面中显示HTML代码,不能让页面解析使用的。

六、打包标签库

我们在自定义了一些自己需要用到的标签之后,可能在别的地方也需要使用,这时我们最好像sun公司一样将其打包成一个jar文件。

先将cn.itcast.web.tag中所有的自定义标签类全部拷贝到一个普通java工程中的src目录下面,这时会发现有错误,这时因为我们没有导入相应的包,这里我们需要将tomcat中的E:\software\tomcat\lib中的jsp-api.jarservlet-api.jar两个包拷贝到新建的lib包中,然后导入即可。最后还需要将配置文件itcast.tld拷贝到新建目录META-INF目录中。这里我们可以看到需要建立一个lib包保存相关的jar包,而META-INF中一般保存相关的配置文件。然后选中工程右键->Export->Java->JAR file->Next->选中要打包的工程,同时将右边框中MyEclipse的配置文件取消选中,然后在JAR file选择要保存的路径和文件名,文件名后缀必须为.jar,然后点击finish即可。

最后:

这些标签其实sun公司已经帮我写好了,我们只需要拿过来用即可。这里只是让我们更好的明白其是怎样实现的,以后碰到特殊的标签我们可以自己开发。

你可能感兴趣的:(15.自定义标签开发案例(我的JavaEE笔记))