JSP自定義標籤
mvvm框架盛行的今天jsp視乎已經out了,但是由於歷史原因jsp使用範圍依舊十分廣泛。(本人 喜歡jsp ,在標籤開發的效率上,jsp要比vue低很多,並且前後端分離的開發模式,在除錯,部署,分工都要好很多。)
第一步 : jsp標籤的描述,宣告
jsp標籤需要使用xml描述(這裡的檔案格式是tld,依舊認為這就是xml)
<?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>jsp Label</description> <!-- 版本 --> <tlib-version>1.0</tlib-version> <!-- 短名 --> <short-name>kgo</short-name> <!-- 指定標籤庫URI --> <uri>/WEB-INF/JSPLabel.tld</uri> <!-- 佈局標籤 --> <tag> <description>Layout</description> <!-- 標籤庫名字 --> <name>Layout</name> <!-- 標籤處理類 --> <tag-class>com.telchina.label.ContainerLabel</tag-class> <!-- 標籤體內容 --> <body-content>scriptless</body-content> <!-- 標籤屬性:driver --> <attribute> <name>layHeight</name> <required>false</required> <fragment>true</fragment> </attribute> <attribute> <name>layClass</name> <required>true</required> <fragment>true</fragment> </attribute> </tag> <!-- 卡片標籤 --> <tag> <description>jsp卡片</description> <!-- 標籤庫名字 --> <name>Card</name> <!-- 標籤處理類 --> <tag-class>com.telchina.label.CardLabel</tag-class> <!-- 標籤體內容 --> <body-content>scriptless</body-content> <!-- 標籤屬性:driver --> <attribute> <name>title</name> <required>true</required> <fragment>true</fragment> </attribute> </tag> <!-- 卡片標籤 --> <tag> <description>jsp輪播</description> <!-- 標籤庫名字 --> <name>carousel</name> <!-- 標籤處理類 --> <tag-class>com.telchina.label.CarouselLabel</tag-class> <!-- 標籤體內容 --> <body-content>scriptless</body-content> <!-- 標籤屬性 --> <attribute> <name>id</name> <required>true</required> <fragment>true</fragment> </attribute> </tag> </taglib>
這裡講一下幾個重要的屬性:
1)body-content 有如下四個屬性
tagdependent:標籤體內容直接被寫入BodyContent,由自定義標籤類來進行處理,而不被JSP容器解釋,
如下:
<test:myList>
select name,age from users
</test:myList>
JSP:接受所有JSP語法,如定製的或內部的tag、scripts、靜態HTML、指令碼元素、JSP指令和動作。如:
<my:test>
<%=request.getProtocol()%>
</my:test>
具體可參考後面附原始碼。
empty:空標記,即起始標記和結束標記之間沒有內容。
下面幾種寫法都是有效的,
<test:mytag />
<test:mytag uname="Tom" />
<test:mytag></test:mytag>
scriptless:接受文字、EL和JSP動作。如上述②使用<body-content> scriptless </body-content>則報錯,具體可參考後面附原始碼。
注意:scriptless聲明後標籤內部不能為空。
2)required 引數是否必須
第二步:書寫jsp標籤的實現類
已上訴jsp標籤中的Card標籤為例
package com.kgo.label;
import java.io.IOException;
import java.io.StringWriter;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.SimpleTagSupport;
public class CardLabel extends SimpleTagSupport {
private StringBuffer head_buffer = new StringBuffer();
private StringBuffer foot_buffer = new StringBuffer();
// 屬性
private String title = "jsp卡片標籤";
private StringWriter sw = new StringWriter();
public void doTag() throws JspException, IOException {
JspWriter out = getJspContext().getOut();
printHead();
out.println(head_buffer.toString());
getJspBody().invoke(sw);
getJspContext().getOut().println(sw.toString());
printFoot();
out.println(foot_buffer.toString());
}
private void printHead() {
head_buffer.append(String.format("<div class=\"%s %s\">%n", "layui-card", "kgo-card"));
head_buffer.append(String.format(" <div class=\"%s\">%s</div>", "layui-card-header", title));
head_buffer.append(String.format(" <div class=\"%s %s\">%n", "layui-card-body", "kgo-card-body"));
}
private void printFoot() {
foot_buffer.append(String.format(" </div>%n"));
foot_buffer.append(String.format("</div>%n"));
foot_buffer.append(String.format("<script>"));
foot_buffer.append(String.format("layui.use(['element','jquery'], function(){%n"));
foot_buffer.append(String.format(" var element = layui.element; %n"));
foot_buffer.append(String.format(" var $ = layui.jquery;%n "));
foot_buffer.append(String.format(" });%n"));
foot_buffer.append(String.format("</script>"));
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
實現基本是這樣:
屬性 在tld裡進行宣告,在實現類中宣告同名(必須同名)的私有變數,並新增set和get方法。
入口 我這裡繼承了SimpleTagSupport物件(jsp2.0以及以上版本才能使用該物件)入好函式則為 doTag() 方法。
列印 開始dom
JspWriter out = getJspContext().getOut();
out.println(head_buffer.toString());
這個標籤可以巢狀其他標記進行使用,因此這裡列印的是上半部分dom
private void printHead() {
head_buffer.append(String.format("<div class=\"%s %s\">%n", "layui-card", "kgo-card"));
head_buffer.append(String.format(" <div class=\"%s\">%s</div>", "layui-card-header", title));
head_buffer.append(String.format(" <div class=\"%s %s\">%n", "layui-card-body", "kgo-card-body"));
}
這裡是在封裝layui標籤,使用了一下字串格式化,但是由於時間太匆忙未進行完善的封裝
喚醒嵌入的dom(可以不是dom,可以是文字,其他jsp標籤都可以)
getJspBody().invoke(sw);
getJspContext().getOut().println(sw.toString());
這裡就是列印嵌入在標籤內部的dom結構。
列印 結束dom
printFoot();
out.println(foot_buffer.toString());
列印的dom結構如下:
private void printFoot() {
foot_buffer.append(String.format(" </div>%n"));
foot_buffer.append(String.format("</div>%n"));
foot_buffer.append(String.format("<script>"));
foot_buffer.append(String.format("layui.use(['element','jquery'], function(){%n"));
foot_buffer.append(String.format(" var element = layui.element; %n"));
foot_buffer.append(String.format(" var $ = layui.jquery;%n "));
foot_buffer.append(String.format(" });%n"));
foot_buffer.append(String.format("</script>"));
}
第三步:webXML宣告
<jsp-config>
<taglib>
<taglib-uri>/WEB-INF/JSPLabel.tld</taglib-uri>
<taglib-location>/WEB-INF/JSPLabel.tld</taglib-location>
</taglib>
</jsp-config>
tld標籤可以被打包進jar包,jstl標籤就是這樣的,這裡我還沒有做,日後補充。