之前我没看过core包内的类的源码,甚至不知道还有tagplugin,前面的回答基于我的直觉。不过既然你这么认真,我就去找了找源码。代码支持了我的推测。
[quote]org.apache.jasper.compiler.tagplugin
Interface TagPlugin
All Known Implementing Classes:
Catch, Choose, ForEach, ForTokens, If, Import, Otherwise, Out, Param, Redirect, Remove, Set, Url, When [/quote]
只有其中Choose,ForEach,If,Otherwise,Out,When 这五个逻辑控制类是final,其他是public。我想这应该能体现出作者希望被别人继承的目的了吧,否则他没必要这样取舍。
至于什么时候需要写插件不是很清楚吗?——在你需要自定义如何翻译jsp到java代码的时候——这问题也需要具体问题具体分析。
我们来看看其中的一个类的源码:
[code="java"]
package org.apache.jasper.tagplugins.jstl.core;
import org.apache.jasper.compiler.tagplugin.TagPlugin;
import org.apache.jasper.compiler.tagplugin.TagPluginContext;
public class Param implements TagPlugin {
public void doTag(TagPluginContext ctxt) {
//don't support the body content
//define names of all the temp variables
String nameName = ctxt.getTemporaryVariableName();
String valueName = ctxt.getTemporaryVariableName();
String urlName = ctxt.getTemporaryVariableName();
String encName = ctxt.getTemporaryVariableName();
String index = ctxt.getTemporaryVariableName();
//if the param tag has no parents, throw a exception
TagPluginContext parent = ctxt.getParentContext();
if(parent == null){
ctxt.generateJavaSource(" throw new JspTagExcption" +
"(\"<param> outside <import> or <urlEncode>\");");
return;
}
//get the url string before adding this param
ctxt.generateJavaSource("String " + urlName + " = " +
"(String)pageContext.getAttribute(\"url_without_param\");");
//get the value of "name"
ctxt.generateJavaSource("String " + nameName + " = ");
ctxt.generateAttribute("name");
ctxt.generateJavaSource(";");
//if the "name" is null then do nothing.
//else add such string "name=value" to the url.
//and the url should be encoded
ctxt.generateJavaSource("if(" + nameName + " != null && !" + nameName + ".equals(\"\")){");
ctxt.generateJavaSource(" String " + valueName + " = ");
ctxt.generateAttribute("value");
ctxt.generateJavaSource(";");
ctxt.generateJavaSource(" if(" + valueName + " == null) " + valueName + " = \"\";");
ctxt.generateJavaSource(" String " + encName + " = pageContext.getResponse().getCharacterEncoding();");
ctxt.generateJavaSource(" " + nameName + " = java.net.URLEncoder.encode(" + nameName + ", " + encName + ");");
ctxt.generateJavaSource(" " + valueName + " = java.net.URLEncoder.encode(" + valueName + ", " + encName + ");");
ctxt.generateJavaSource(" int " + index + ";");
ctxt.generateJavaSource(" " + index + " = " + urlName + ".indexOf(\'?\');");
//if the current param is the first one, add a "?" ahead of it
//else add a "&" ahead of it
ctxt.generateJavaSource(" if(" + index + " == -1){");
ctxt.generateJavaSource(" " + urlName + " = " + urlName + " + \"?\" + " + nameName + " + \"=\" + " + valueName + ";");
ctxt.generateJavaSource(" }else{");
ctxt.generateJavaSource(" " + urlName + " = " + urlName + " + \"&\" + " + nameName + " + \"=\" + " + valueName + ";");
ctxt.generateJavaSource(" }");
ctxt.generateJavaSource(" pageContext.setAttribute(\"url_without_param\"," + urlName + ");");
ctxt.generateJavaSource("}");
}
}
[/code] [url]http://www.google.com/codesearch/p?hl=zh-CN#cM_OVOKybvs/tomcat/tomcat-6/v6.0.10/src/apache-tomcat-6.0.10-src.zip|KNqCNnRERSg/apache-tomcat-6.0.10-src/java/org/apache/jasper/tagplugins/jstl/core/Param.java&q=org.apache.jasper.tagplugins.jstl.core.url&d=13[/url]
从注释和代码可以分析出这个Param类是用来翻译url后的查询参数的,如果你不同意它生成的java代码,譬如想把" String " + encName + " = pageContext.getResponse().getCharacterEncoding();"这里的编码写死为utf8,你当然就可以继承Param.java,用你的代码覆写它。部署以后tomcat就会按你的意愿来翻译了。
还要解释吗?
还有更复杂的需求,例如我们知道如果一个jsp太复杂以致某个生成的java block超过了64k,javac就会发生编译错误。我们一般用include来切分页面,有了tagplugin机制,你可以自定义自己的翻译程序,自动把大jsp翻译成几个java文件来规避变异错误。