利用JSP实现动态页面,常常会写一个自定义标签来实现页面的组件化设计。一般是写一个类让它继承TagSupport类,然后将页面的逻辑封装在TagSupport中,然后在tld文件中添加自定义标签的属性及标签名称声明。 之后就可以在jsp页面使用自定义标签了,以上提到的自定义标签只是一个大概,在此不赘述了。
另外实现页面组件化设计还有另外一个途径,那就是通过tagplugin来实现。
package org.apache.jasper.compiler.tagplugin; public interface TagPlugin { void doTag(TagPluginContext ctxt); }
package org.apache.jasper.compiler.tagplugin; public interface TagPluginContext { boolean isScriptless(); // 是否设置了自定义标签上的值 boolean isAttributeSpecified(String attribute); // 以该自定义标签为上线文,取得该自定义标签所对应的临时变量名 String getTemporaryVariableName(); // 在JSP生成java文件的过程中会在import区块中导入import的内容 void generateImport(String s); // void generateDeclaration(String id, String text); /** * Generate Java source codes */ void generateJavaSource(String s); // boolean isConstantAttribute(String attribute); // 取得自定义标签定义的属性值,isAttributeSpecified()方法为查询该属性值是否有值 String getConstantAttribute(String attribute); // 由于属性值是可以写el的,所以在标签生成结果时候,会在生成java文件的过程中自动调用解析el语法的功能模块 void generateAttribute(String attribute); // 生成自定义标签的body内容,注意:如果在doTag函数中中没有调用该方法的话,tagmanager会在标签解析呃呃最后自动调用标签的内容块 void generateBody(); void dontUseTagPlugin(); TagPluginContext getParentContext(); void setPluginAttribute(String attr, Object value); Object getPluginAttribute(String attr); }
以上这两个接口是包装在tomcat的jasper.jar这个jar包中的。
首先,写一个类实现TagPlugin 接口:
public class NameTagPlugin implements TagPlugin { private static int count = 1; public void doTag(TagPluginContext ctx) { System.out.println(ctx.getTemporaryVariableName()); ctx.generateDeclaration("cssDependants","private static final java.util.List css_dependants = new java.util.ArrayList(1); "); if (ctx.isAttributeSpecified("name")) { ctx.generateDeclaration("cssDependantsPath" + (count++), "static{css_dependants.add(\"" + ctx.getConstantAttribute("name") + "\");}"); } System.out.println(ctx.getConstantAttribute("name")); } }
注意:以上这个类需要放在 $catalina_home$/common/classes这个目录下,因为tagplugin这个类是在jsp编译成java文件的时候调用的,当java文件被编译成class字节码之后就不会调用tagplugin了。
TagPluginContext类的generateDeclaration有两个参数,id和 content,当在一个pagecontext中重复调用generateDeclaration()这个方法如果前后两次调用id参数是一样的,那么在java文件中生成的declaration块就会显示第一次调用所输入content内容。
以上这段代码会使自定义标签编译成java文件的时候生成,如下内容(代码片段):
public final class nametagtest_jsp extends org.apache.jasper.runtime.HttpJspBase implements org.apache.jasper.runtime.JspSourceDependent { private static final java.util.List css_dependants = new java.util.ArrayList(1); static{css_dependants.add("hello");} static{css_dependants.add("code");} private static java.util.List _jspx_dependants; static { _jspx_dependants = new java.util.ArrayList(1); _jspx_dependants.add("/WEB-INF/koubeitagtest.tld"); }
再写一个自定义标签(这个尽量简单一些,写一个类似helloworld的就行了)
public class TestTag extends TagSupport { private String name; public int doStartTag() throws JspException { try { this.pageContext.getOut().write(name); } catch (IOException e) { throw new JspException(e); } return EVAL_BODY_INCLUDE; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
将自定义标签声明在/WEB-INF/koubeitagtest.tld,这个文件中。
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <taglib xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"> <display-name>koubeitest</display-name> <tlib-version>2.2.4</tlib-version> <short-name>tt</short-name> <uri>koubeitest-tags</uri> <tag> <name>name</name> <tag-class>com.koubei.example.tag.TestTag</tag-class> <body-content>JSP</body-content> <attribute> <name>name</name> <required>false</required> <rtexprvalue>false</rtexprvalue> </attribute> </tag> </taglib>
创建tagPlugins.xml文件,注意文件名不能有错误,大小写不能错。存放在WEB-INF文件夹下,当时我因为文件名写成了tagplugin.xml造成plugin没有起作用。
<?xml version="1.0"?> <tag-plugins> <tag-plugin> <tag-class>com.koubei.example.tag.TestTag</tag-class> <plugin-class>com.koubei.example.tag.NameTagPlugin</plugin-class> </tag-plugin> </tag-plugins>