jasper 获取当前日期_入侵Jasper以获取JSP页面的对象模型

jasper 获取当前日期

为了对我的JSP执行一些检查和统计分析,我需要一个包含在其中的元素的类似于DOM的层次模型。 但是,解析JSP页面并不是一件容易的事,最好留给它一个出色的工具-Tomcat,Jetty,GlassFish以及其他所有工具都可以使用Jasper JSP编译器。

有一种简单的方法可以调整它以生成所需的任何输出,以将JSP转换为所需的任何形式,包括页面的对象模型:

  1. 定义一个Node.Visitor子类来处理JSP的节点(标签等)
  2. 编写一个简单的Compiler子类,重写其generateJava()来调用访问者
  3. 继承编译器执行程序JspC的子类,重写其方法getCompilerClassName()以返回您自己的编译器的类

让我们看一下代码。

实作

1.自定义访问者

编译器将调用Visitor来处理已解析的JSP的树对象模型。 此实现仅打印有关页面中有趣的节点子集的信息,以使其嵌套清晰。

package org.apache.jasper.compiler;

import java.util.LinkedList;
import org.apache.jasper.JasperException;
import org.apache.jasper.compiler.Node.CustomTag;
import org.apache.jasper.compiler.Node.ELExpression;
import org.apache.jasper.compiler.Node.IncludeDirective;
import org.apache.jasper.compiler.Node.Visitor;
import org.xml.sax.Attributes;

public class JsfElCheckingVisitor extends Visitor {

    private String indent = "";

    @Override
    public void visit(ELExpression n) throws JasperException {
        logEntry("ELExpression", n, "EL: " + n.getEL());
        super.visit(n);
    }

    @Override
    public void visit(IncludeDirective n) throws JasperException {
        logEntry("IncludeDirective", n, toString(n.getAttributes()));
        super.visit(n);
    }

    @Override
    public void visit(CustomTag n) throws JasperException {
        logEntry("CustomTag", n, "Class: " + n.getTagHandlerClass().getName() + ", attrs: "
                + toString(n.getAttributes()));

        doVisit(n);

        indent += " ";
        visitBody(n);
        indent = indent.substring(0, indent.length() - 1);
    }

    private String toString(Attributes attributes) {
        if (attributes == null || attributes.getLength() == 0) return "";
        LinkedList<String> details = new LinkedList<String>();

        for (int i = 0; i < attributes.getLength(); i++) {
            details.add(attributes.getQName(i) + "=" + attributes.getValue(i));
        }

        return details.toString();
    }

    private void logEntry(String what, Node n, String details) {
        System.out.println(indent + n.getQName() + " at line:"
                + n.getStart().getLineNumber() + ": " + details);
    }

}

笔记:

  • 访客必须位于org.apache.jasper.compiler包中,因为基本类org.apache.jasper.compiler.Node是包私有的
  • visitBody方法触发对嵌套节点的处理
  • 还有更多我可以覆盖的方法(和通行方法doVisit),但是我只选择了对我来说有趣的那些方法
  • 节点的属性为... sax类型。 Attributes ,它包含属性名称和值作为字符串
    • attribute.getType(i)通常是CDATA
  • Node结构包含有关父节点,标签名称,标签处理程序类,源文件的相应行以及源文件的名称的信息以及其他有用信息
  • CustomTag可能是最有趣的节点类型,例如,所有JSF标签都属于这种类型

输出示例(对于JSF页面)

jsp:directive.include at line:5: [file=includes/stdjsp.jsp]
jsp:directive.include at line:6: [file=includes/ssoinclude.jsp]
f:verbatim at line:14: Class: com.sun.faces.taglib.jsf_core.VerbatimTag, attrs:
htm:div at line:62: Class: com.exadel.htmLib.tags.DivTag, attrs: [style=width:100%;]
 h:form at line:64: Class: com.sun.faces.taglib.html_basic.FormTag, attrs: [id=inputForm]
  htm:table at line:66: Class: com.exadel.htmLib.tags.TableTag, attrs: [cellpadding=0, width=100%, border=0, styleClass=clear box_main]
   htm:tr at line:71: Class: com.exadel.htmLib.tags.TrTag, attrs:
    htm:td at line:72: Class: com.exadel.htmLib.tags.TdTag, attrs:
    f:subview at line:73: Class: com.sun.faces.taglib.jsf_core.SubviewTag, attrs: [id=cars]
      jsp:directive.include at line:74: [file=/includes/cars.jsp]
      h:panelGroup at line:8: Class: com.sun.faces.taglib.html_basic.PanelGroupTag, attrs: [rendered=#{bookingHandler.flowersAvailable}]
...
   htm:tr at line:87: Class: com.exadel.htmLib.tags.TrTag, attrs: [style=height:5px]
    htm:td at line:87: Class: com.exadel.htmLib.tags.TdTag, attrs:

(我不打印“关闭标签”,因为很明显,当缩进相同或较小的另一个节点出现或输出结束时,标签结束。)

2.编译器子类

重要的部分是我刚刚复制的generateJava,从中删除了一些代码并添加了对Visitor的调用。 所以实际上下面清单中的3行是新的(6,56,70)

public class OnlyReadingJspPseudoCompiler extends Compiler {

    /** We're never compiling .java to .class. */
    @Override protected void generateClass(String[] smap) throws FileNotFoundException,
            JasperException, Exception {
        return;
    }

    /** Copied from {@link Compiler#generateJava()} and adjusted */
    @Override protected String[] generateJava() throws Exception {

        // Setup page info area
        pageInfo = new PageInfo(new BeanRepository(ctxt.getClassLoader(),
                errDispatcher), ctxt.getJspFile());

        // JH: Skipped processing of jsp-property-group in web.xml for the current page

        if (ctxt.isTagFile()) {
            try {
                double libraryVersion = Double.parseDouble(ctxt.getTagInfo()
                        .getTagLibrary().getRequiredVersion());
                if (libraryVersion < 2.0) {
                    pageInfo.setIsELIgnored("true", null, errDispatcher, true);
                }
                if (libraryVersion < 2.1) {
                    pageInfo.setDeferredSyntaxAllowedAsLiteral("true", null,
                            errDispatcher, true);
                }
            } catch (NumberFormatException ex) {
                errDispatcher.jspError(ex);
            }
        }

        ctxt.checkOutputDir();

        try {
            // Parse the file
            ParserController parserCtl = new ParserController(ctxt, this);

            // Pass 1 - the directives
            Node.Nodes directives =
                parserCtl.parseDirectives(ctxt.getJspFile());
            Validator.validateDirectives(this, directives);

            // Pass 2 - the whole translation unit
            pageNodes = parserCtl.parse(ctxt.getJspFile());

            // Validate and process attributes - don't re-validate the
            // directives we validated in pass 1
            /**
             * JH: The code above has been copied from Compiler#generateJava() with some
             * omissions and with using our own Visitor.
             * The code that used to follow was just deleted.
             * Note: The JSP's name is in ctxt.getJspFile()
             */
            pageNodes.visit(new JsfElCheckingVisitor());

        } finally {}

        return null;
    }

    /**
     * The parent's implementation, in our case, checks whether the target file
     * exists and returns true if it doesn't. However it is expensive so
     * we skip it by returning true directly.
     * @see org.apache.jasper.JspCompilationContext#getServletJavaFileName()
     */
    @Override public boolean isOutDated(boolean checkClass) {
        return true;
    }

}

笔记:

  • 我从生成Java中删除了许多对我来说不重要的代码; 对于与我预期不同的分析类型,某些代码可能会有用,因此请查看原始的Compiler类,然后自己决定。
  • 我不太在乎JSP EL,因此可以优化编译器,使其仅需一次通过。

3.编译器执行器

直接使用编译器很困难,因为它取决于许多复杂的设置和对象。 因此,最简单的方法是重用Ant任务JspC,这还有查找要处理的JSP的额外好处。 如前所述,关键是重写getCompilerClassName以返回编译器的类(第8行)

import org.apache.jasper.JspC;

/** Extends JspC to use the compiler of our choice; Jasper version 6.0.29. */
public class JspCParsingToNodesOnly extends JspC {

    /** Overriden to return the class of ours (default = null => JdtCompiler) */
    @Override public String getCompilerClassName() {
        return OnlyReadingJspPseudoCompiler.class.getName();
    }

    public static void main(String[] args) {
        JspCParsingToNodesOnly jspc = new JspCParsingToNodesOnly();

        jspc.setUriroot("web"); // where to search for JSPs
        //jspc.setVerbose(1);     // 0 = false, 1 = true
        jspc.setJspFiles("helloJSFpage.jsp"); // leave unset to process all; comma-separated

        try {
            jspc.execute();
        } catch (JasperException e) {
            throw new RuntimeException(e);
        }
    }
}

笔记:

  • JspC通常会在指定的Uriroot下找到所有文件,但是您可以通过将其逗号分隔的名称传递给setJspFiles来告诉它忽略所有选定的文件。

编译依赖

以您的常春藤形式:

<dependency name="jasper" org="org.apache.tomcat" rev="6.0.29">
<dependency name="jasper-jdt" org="org.apache.tomcat" rev="6.0.29">
<dependency name="ant" org="org.apache.ant" rev="1.8.2">

执照

这里的所有代码都直接来自Jasper,因此属于同一许可证,即Apache许可证,版本2.0

结论

Jasper并不是真正为扩展和模块化而设计的,因为关键的Node类是程序包私有的,并且其API非常复杂,以致仅重用其中的一部分非常困难。 幸运的是,通过提供一些“伪”对象,Ant任务JspC使它可以在servlet容器之外使用,并且有一种方法可以通过很少的工作来调整它以满足我们的需求,尽管要弄清楚它并不容易。 我不得不应用一些肮脏的技巧,即使用包私有类中的内容,并覆盖一个不打算被覆盖的方法( generateJava ),但它可以工作并提供非常有价值的输出,这使得您可以做任何想做的事情用一个JSP来做。

快乐的编码...
拜伦
相关文章:

翻译自: https://www.javacodegeeks.com/2011/06/hacking-jasper-to-get-object-model-of.html

jasper 获取当前日期

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值