14/08/2018, 11:03

Custom Tags (Thẻ tùy biến) trong JSP

Một custom tag là một phần tử JSP được định nghĩa bởi người sử dụng. Khi một JSP page chứa một custom tag được phiên dịch thành một Servlet, thẻ này được biến đổi để hoạt động trên một đối tượng đã gọi một Tag Handler. Sau đó, Web container triệu hồi các hoạt động này khi Servlet của JSP ...

Một custom tag là một phần tử JSP được định nghĩa bởi người sử dụng. Khi một JSP page chứa một custom tag được phiên dịch thành một Servlet, thẻ này được biến đổi để hoạt động trên một đối tượng đã gọi một Tag Handler. Sau đó, Web container triệu hồi các hoạt động này khi Servlet của JSP page được thực thi.

Sự kế thừa của các JSP tag giúp bạn tạo các thẻ mới mà bạn có thể chèn một cách trực tiếp vào trong một JSP page, như khi bạn thực hiện với các thẻ có sẵn (built-in) trong các chương trước đã giới thiệu. JSP 2.0 Specification giới thiệu Simple Tag Handler để viết các Custom Tag này.

Để viết một custom tag, đơn giản bạn có thể kế thừa lớp SimpleTagSupport và ghi đè phương thức doTag(), tại đây bạn có thể đặt code của bạn để tạo content cho thẻ đó.

Tạo thẻ "Hello" trong JSP

Giả sử bạn muốn định nghĩa một custom tag tên là <ex:Hello> và bạn muốn sử dụng nó trong kiểu mà không có phần thân như sau:

<ex:Hello />

Để tạo một Custom Tag trong JSP, đầu tiên bạn phải tạo một lớp Java mà hoạt động như là một Tag Handler. Vì thế, chúng ta tạo HelloTag class như sau:

package com.tutorialspoint;

import javax.servlet.jsp.tagext.*;
import javax.servlet.jsp.*;
import java.io.*;

public class HelloTag extends SimpleTagSupport {

  public void doTag() throws JspException, IOException {
    JspWriter out = getJspContext().getOut();
    out.println("Hello Custom Tag!");
  }
}

Code trên có mã hóa đơn giản, với phương thức doTag() nhận đối tượng JspContext hiện tại bởi sử dụng phương thức getJspContext() và sử dụng nó để gửi "Hello Custom Tag!" tới đối tượng JspWriter hiện tại.

Biên dịch lớp trên và copy nó trong một thư mục có sẵn trong biến môi trường CLASSPATH. Cuối cùng, tạo file thư viện thẻ sau: <Tomcat-Installation-Directory>webappsROOTWEB-INFcustom.tld.

<taglib>
  <tlib-version>1.0</tlib-version>
  <jsp-version>2.0</jsp-version>
  <short-name>Example TLD</short-name>
  <tag>
    <name>Hello</name>
    <tag-class>com.tutorialspoint.HelloTag</tag-class>
    <body-content>empty</body-content>
  </tag>
</taglib>

Bây giờ là lúc sử dụng custom tag là Hello đã định nghĩa trên trong chương trình JSP như sau:

<%@ taglib prefix="ex" uri="WEB-INF/custom.tld"%>
<html>
  <head>
    <title>A sample custom tag</title>
  </head>
  <body>
    <ex:Hello/>
  </body>
</html>

Thử gọi JSP trên và nó sẽ cho kết quả sau:

Hello Custom Tag!

Truy cập phần thân thẻ trong JSP

Bạn có thể bao một message trong phần thân của Custom Tags như khi bạn đã thấy với các thẻ chuẩn. Giả sử bạn muốn định nghĩa một custom tag với tên <ex:Hello> và bạn muốn sử dụng nó trong kiểu có một phần thân thẻ:

<ex:Hello>
   This is message body
</ex:Hello>

Chúng ta sửa đổi code trên một chút để xử lý phần thân cho thẻ:

package com.tutorialspoint;

import javax.servlet.jsp.tagext.*;
import javax.servlet.jsp.*;
import java.io.*;

public class HelloTag extends SimpleTagSupport {

   StringWriter sw = new StringWriter();
   public void doTag()
      throws JspException, IOException
    {
       getJspBody().invoke(sw);
       getJspContext().getOut().println(sw.toString());
    }

}

Trong trường hợp này, kết quả từ sự triệu hồi, đầu tiên được bắt vào trong một StringWriter trước khi được ghi tới JspWriter mà liên kết với thẻ đó. Bây giờ, theo đó, chúng ta cần thay đổi TLD file như sau:

<taglib>
  <tlib-version>1.0</tlib-version>
  <jsp-version>2.0</jsp-version>
  <short-name>Example TLD with Body</short-name>
  <tag>
    <name>Hello</name>
    <tag-class>com.tutorialspoint.HelloTag</tag-class>
    <body-content>scriptless</body-content>
  </tag>
</taglib>

Chúng ta gọi thẻ trên với phần thân chính xác như sau:

<%@ taglib prefix="ex" uri="WEB-INF/custom.tld"%>
<html>
  <head>
    <title>A sample custom tag</title>
  </head>
  <body>
    <ex:Hello>
        This is message body
    </ex:Hello>
  </body>
</html>

Nó sẽ cho kết quả:

This is message body

Thuộc tính của Custom Tag trong JSP

Bạn có thể sử dụng các thuộc tính đa dạng cùng với các thẻ custom tag của bạn. Để chấp nhận một giá trị thuộc tính, một lớp custom tag cần triển khai các phương thức setter, như phương thức setter trong JavaBeans như sau:

package com.tutorialspoint;

import javax.servlet.jsp.tagext.*;
import javax.servlet.jsp.*;
import java.io.*;

public class HelloTag extends SimpleTagSupport {

   private String message;

   public void setMessage(String msg) {
      this.message = msg;
   }

   StringWriter sw = new StringWriter();

   public void doTag()
      throws JspException, IOException
    {
       if (message != null) {
          /* Use message from attribute */
          JspWriter out = getJspContext().getOut();
          out.println( message );
       }
       else {
          /* use message from the body */
          getJspBody().invoke(sw);
          getJspContext().getOut().println(sw.toString());
       }
   }

}

Tên của thuộc tính là "message", vì thể phương thức setter là setMessage(). Bây giờ chúng ta thêm thuộc tính này trong TLD file bởi sử dụng phần tử <attribute> như sau:

<taglib>
  <tlib-version>1.0</tlib-version>
  <jsp-version>2.0</jsp-version>
  <short-name>Example TLD with Body</short-name>
  <tag>
    <name>Hello</name>
    <tag-class>com.tutorialspoint.HelloTag</tag-class>
    <body-content>scriptless</body-content>
    <attribute>
       <name>message</name>
    </attribute>
  </tag>
</taglib>

Thử JSP trên với thuộc tính message như sau:

<%@ taglib prefix="ex" uri="WEB-INF/custom.tld"%>
<html>
  <head>
    <title>A sample custom tag</title>
  </head>
  <body>
    <ex:Hello message="This is custom tag" />
  </body>
</html>

Nó sẽ cho kết quả sau:

This is custom tag

Hy vọng ví dụ trên sẽ giúp ích cho bạn. Bạn nên ghi nhớ rằng bạn có thể bao các Property cho một thuộc tính:

Property Mục đích
namePhần tử name định nghĩa tên của một thuộc tính. Mỗi tên thuộc tính phải là duy nhất cho một thẻ cụ thể
requiredXác định nếu thuộc tính này được yêu cầu hoặc là tùy ý. Nó sẽ là false cho tùy ý
rtexprvalueKhai báo nếu một giá trị runtime expression cho một thuộc tính thẻ là hợp lệ
typeĐịnh nghĩa kiểu lớp Java cho thuộc tính này. Theo mặc định, nó được xem như là String
Miêu tảSự miêu tả có tính thông tin này có thể được cung cấp
fragmentKhai báo nếu giá trị thuộc tính này nên được đối xử như là một JspFragment.

Ví dụ sau xác định các Property liên quan tới một thuộc tính trong:

.....
    <attribute>
      <name>attribute_name</name>
      <required>false</required>
      <type>java.util.Date</type>
      <fragment>false</fragment>
    </attribute>
.....

Nếu bạn đang sử dụng hai thuộc tính, thì bạn có thể sửa đổi TLD như sau:

.....
    <attribute>
      <name>attribute_name1</name>
      <required>false</required>
      <type>java.util.Boolean</type>
      <fragment>false</fragment>
    </attribute>
    <attribute>
      <name>attribute_name2</name>
      <required>true</required>
      <type>java.util.Date</type>
    </attribute>
.....

0