JSP自定義標籤就是如此簡單

Java3y發表於2019-02-21

為什麼要用到簡單標籤?

上一篇部落格中我已經講解了傳統標籤,想要開發自定義標籤,大多數情況下都要重寫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);
	}

複製程式碼
  • setParent()和getParent()方法就不多說了,我們來看一下剩下的3個方法

		void doTag() throws JspException, IOException;

	    void setJspContext(JspContext var1);
	
	    void setJspBody(JspFragment var1);


複製程式碼
  • 明顯地:
    • doTag()就是我們要寫程式碼處理邏輯地方
    • setJspContext(JspContext var1)是將PageContext物件傳遞給標籤處理器類(PageContext是JspContext的子類)
    • setJspBody(JspFragment var1)把代表標籤體的JspFragment物件傳遞給標籤處理器物件

快速入門

  • 一般地,我們做開發都是繼承SimpleTagSupport類(該類實現了SimpleTag)來編寫自定義標籤

  • 下面我們就來個快速入門吧

  • 目標:傳入字串格式就可以顯示想要的格式日期,對比之前傳統標籤的,看有什麼不同之處

  • 標籤處理器類:


	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;
	    }
	}

複製程式碼
  • tld檔案:

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

複製程式碼
  • 效果:

JSP自定義標籤就是如此簡單

JSP自定義標籤就是如此簡單

  • 簡單標籤的好處就是不用去理會doStartTag、doEndTag、SKIP_BODY以及一系列的方法和屬性!
  • 簡單標籤一個doTag()方法走天下!

SimpleTagSupport類的執行順序:

  • ①WEB容器呼叫標籤處理器物件的setJspContext方法,將代表JSP頁面的pageContext物件傳遞給標籤處理器物件
  • ②WEB容器呼叫標籤處理器物件的setParent方法,將父標籤處理器物件傳遞給這個標籤處理器物件。【注意,只有在標籤存在父標籤的情況下,WEB容器才會呼叫這個方法】
  • ③如果呼叫標籤時設定了屬性,容器將呼叫每個屬性對應的setter方法把屬性值傳遞給標籤處理器物件。如果標籤的屬性值是EL表示式或指令碼表示式,則WEB容器首先計算表示式的值,然後把值傳遞給標籤處理器物件。
  • ④如果簡單標籤有標籤體,容器將呼叫setJspBody方法把代表標籤體的JspFragment物件傳遞進來
  • ⑤執行標籤時:容器呼叫標籤處理器的doTag()方法,開發人員在方法體內通過操作JspFragment物件,就可以實現是否執行、迭代、修改標籤體的目的。

JSP自定義標籤就是如此簡單

深入簡單標籤

在我們講解傳統標籤的時候,配合著SKIP_BODY、SKIP_PAGE等變數可以實現如下的功能:

  1. 控制jsp頁面某一部分內容(標籤體)是否執行
  2. 控制整個jsp頁面是否執行
  3. 控制jsp頁面內容重複執行
  4. 修改jsp頁面內容輸出

  • 簡單標籤可沒有這些變數呀,那它怎麼才能實現上面那些功能呢?

  • 在doTag方法中可以丟擲javax.servlet.jsp.SkipPageException異常,用於通知WEB容器不再執行JSP頁面中位於結束標記後面的內容,這等效於在傳統標籤的doEndTag方法中返回Tag.SKIP_PAGE常量的情況,我們來測試一下,在上面例子的程式碼中新增


	throw new SkipPageException();

複製程式碼
  • 效果:

JSP自定義標籤就是如此簡單

  • 至於其他的功能下面會講到

帶標籤體的簡單標籤

  • SimpleTagSupport也可以帶標籤體,但是處理方法和傳統標籤完全不同

    • 傳統標籤是這樣子的:將標籤體的內容通過setBodyContent()注入到BodyContent物件中。
    • 簡單標籤是這樣子的:通過JspFragment物件實現!
  • 我們來看一下JspFragment物件的原始碼吧



	public 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) :

  • 用於執行JspFragment物件所代表的JSP程式碼片段
  • 引數out用於指定將JspFragment物件的執行結果寫入到哪個輸出流物件中,如果傳遞給引數out的值為null,則將執行結果寫入到JspContext.getOut()方法返回的輸出流物件中。(簡而言之,可以理解為寫給瀏覽器)

  • 下面是標籤處理器類的程式碼

	public class Demo1 extends SimpleTagSupport {
	    @Override
	    public void doTag() throws JspException, IOException {
	
	        //得到代表標籤體的物件
	        JspFragment jspFragment = getJspBody();
	
	        //invoke方法接收的是一個Writer,如果為null,就代表著JspWriter(),將標籤體的資料寫給瀏覽器!
	        jspFragment.invoke(null);
	        
	    }
	}

複製程式碼
  • 效果:

JSP自定義標籤就是如此簡單

  • 既然標籤體的內容是通過JspFragment物件的invoke()方法寫給瀏覽器的,那麼那麼那麼,我只要控制好invoke()方法,我想幹什麼就幹什麼!

  • 也就是說:

    • 不呼叫invoke()方法,標籤體內容就不會輸出到瀏覽器上
    • 重複呼叫invoke()方法,標籤體內容就會被重複執行
    • 若想在標籤處理器中修改標籤體內容,只需在呼叫invoke方法時指定一個可取出結果資料的輸出流物件(例如StringWriter),讓標籤體的執行結果輸出到該輸出流物件中,然後從該輸出流物件中取出資料進行修改後再輸出到目標裝置,即可達到修改標籤體的目的
  • 來來來,我們來試驗一下:

    • 不呼叫invoke()方法
    
        public void doTag() throws JspException, IOException {
    
            //得到代表標籤體的物件
            JspFragment jspFragment = getJspBody();
            
            //jspFragment.invoke(null);
    
        }
    
    複製程式碼
    • 標籤體的內容沒有輸出

      JSP自定義標籤就是如此簡單

    • 呼叫兩次invoke()方法

    
        public void doTag() throws JspException, IOException {
    
            //得到代表標籤體的物件
            JspFragment jspFragment = getJspBody();
    
            jspFragment.invoke(null);
            jspFragment.invoke(null);
    
        }
    
    
    複製程式碼
    • 標籤體的內容被輸出了兩次
      JSP自定義標籤就是如此簡單
    • invoke()方法指定別的輸出流(StringWriter),將標籤體的內容寫到流物件中,再通過流物件把資料取出來,達到修改的目的。
    
            //得到代表標籤體的物件
            JspFragment jspFragment = getJspBody();
    
            //建立可以儲存字串的Writer物件
            StringWriter stringWriter = new StringWriter();
    
            //invoke()方法把標籤體的資料都寫給流物件中
            jspFragment.invoke(stringWriter);
    
            //把流物件的資料取出來,流物件的資料就是標籤體的內容
            String value = stringWriter.toString();
    
            //將資料改成是大寫的,寫到瀏覽器中
            getJspContext().getOut().write(value.toUpperCase());
    
    複製程式碼
    • 標籤體的內容被改成了大寫!

    JSP自定義標籤就是如此簡單

我們可以發現,傳統標籤能完成的功能,簡單標籤都可以完成,並且更為簡單!


自定義標籤的應用

既然我們學了簡單標籤,我們就用簡單標籤來做開發吧!

防盜鏈

在講解request物件的時候,我們講解過怎麼實現防盜鏈的功能。現在我們使用標籤來進行防盜鏈

模擬下場景:1.jsp頁面是海賊王資源,2.jsp頁面提示非法盜鏈,index1.jsp是我的首頁。別人想要看我的海賊王資源,就必須通過我的首頁點進去看,否則就是非法盜鏈!

  • 標籤處理器的程式碼

    @Override
    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();
        }
    }

複製程式碼
  • 1.jsp程式碼:

	<zhongfucheng:Referer/>
	<html>
	<head>
	    <title></title>
	</head>
	<body>
	
	海賊王最新資源
	
	</body>
	</html>

複製程式碼
  • index1.jsp程式碼

	<h1>這是首頁!</h1>
	<a href="${pageContext.request.contextPath}/1.jsp"> 海賊王最新資源</a>

複製程式碼
  • 2.jsp程式碼

	<body>
	你是非法盜鏈的!!!!!!
	</body>

複製程式碼
  • **第一次我是直接訪問1.jsp,Referer是為空的,所以是非法盜鏈。第二次我是通過從首頁點進去看的,所以可以訪問1.jsp。**效果圖:

JSP自定義標籤就是如此簡單


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;
	    }
	}


複製程式碼
  • tld檔案的程式碼

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

複製程式碼
  • 本來就沒有user這個域物件屬性,所以user就是為null

JSP自定義標籤就是如此簡單

  • 將user改成不為null,瀏覽器就沒有輸出了

JSP自定義標籤就是如此簡單


forEach標籤

forEach標籤最基本的功能:遍歷集合、陣列

  • 首先,我先寫一個可以遍歷List集合的標籤,可能我們會這樣設計

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;
    }
}

複製程式碼

上面的思路是正常的,但是做不下去!我們換一個思路唄。上面的問題主要是在標籤體獲取不到被遍歷出來的物件

我們這樣做:把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;
    }
}


複製程式碼
  • tld檔案如下

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


複製程式碼
  • 測試的jsp程式碼如下

	<%
	    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>


複製程式碼
  • 效果:

JSP自定義標籤就是如此簡單

上面寫的僅僅能夠遍歷List集合,做一個通用的forEach標籤麻煩的是在:不知道傳進來的是什麼型別的陣列、什麼型別集合!,需要逐一去判斷

  • 我們的實現思路就是將所有的集合或陣列都轉成是Collection型別的!

  • 我們來嘗試著寫一下


        //如果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();
        }
		
		//物件陣列
        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);
        }
    }

複製程式碼
  • 效果:

JSP自定義標籤就是如此簡單

  • 對於八大基本型別資料我們就可以這樣幹


        if (items instanceof int[]) {
            int[] ints = (int[]) items;
            collection = new ArrayList();
            for (int anInt : ints) {
                collection.add(anInt);
            }
            
        }
        //......這裡還要寫7個

複製程式碼
  • JSTL的forEach標籤類似就是這樣乾的

JSP自定義標籤就是如此簡單

由於JDK5的新特性,我們又有另外的解決方案,Class物件能夠判斷是否為陣列類,reflect反射包下Array類

  • 其實,無論Map集合、還是任何型別的陣列、都可以使用Colletion進行遍歷!。

  • 如果是八大基本資料型別的陣列,我們就使用反射來進行構建出Collection集合。

  • 標籤處理器的程式碼


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);
        }
    }
}

複製程式碼
  • tld檔案和上面是一樣的,下面是測試程式碼


<%
    /*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>



複製程式碼
  • 效果:

JSP自定義標籤就是如此簡單


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());
    }
}


複製程式碼
  • 測試程式碼
	
	<zhongfucheng:filter><a href="2.jsp">你好啊</a> </zhongfucheng:filter>
	
	<br>
	<a href="2.jsp">你好啊


複製程式碼
  • 效果:

JSP自定義標籤就是如此簡單


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標籤體的內容。

看程式就容易理解上面那句話了:

  • choose標籤處理器

	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;
	    }
	}


複製程式碼
  • When標籤處理器

	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;
	    }
	}

複製程式碼
  • OtherWise標籤處理器


	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);
	
	        }
	    }
	}


複製程式碼
  • 測試程式碼:

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

複製程式碼
  • 效果:

JSP自定義標籤就是如此簡單


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())));
	    }
	}

複製程式碼
  • tld檔案,注意要把dynamic-attribute設定為true


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

複製程式碼
  • 效果,double在運算的時候會丟失精度的,現在只是測驗下動態屬性,這裡就不詳細說了!

JSP自定義標籤就是如此簡單

開發自定義函式

至於怎麼開發自定義函式,在EL表示式的部落格中有

如果文章有錯的地方歡迎指正,大家互相交流。習慣在微信看技術文章的同學,可以關注微信公眾號:Java3y

相關文章