Struts2标签原理分析

0x00 标签使用

1.需求

Struts2标签库提供了主题、模板支持,极大地简化了视图页面的编写。而且struts2的主题、模板都提供了很好的扩展性,实现了更好的代码复用。Struts2允许在页面中使用自定义组件,这完全能满足项目中页面显示复杂,多变的需求。
使用struts2的标签的jsp页面,需要头声明:<%@ taglib uri ="/struts-tags" prefix ="s" %>
用struts2开发的人员使用标签,会加速开发进程。

2.样例使用

首先,建立一个ok.jsp的文件,里面使用标签实现一个链接的编写。
ok.jsp页面如下:

<s:url>标签生成了一个变量名为url的链接字符串。然后使用<s:a>标签通过OGNL语句%{#url}获取该链接。
效果如下:

0x01 Struts2标签工作原理

1.配置

Struts2-core核心jar包里面定义了各个标签的属性以及处理类等内容。文件名为:META-INF/struts-tags.tld
在里面可以找到标签的定义如下:

其中包含了对标签的定义,<tag-class>org.apache.struts2.views.jsp.URLTag</tag-class>说明了标签的具体实现类为org.apache.struts2.views.jsp.URLTag
另外定义了标签的各个属性。比如action,anchor等~
现在来查看下org.apache.struts2.views.jsp.URLTag类,

看到该类继承了ContextBeanTag类,里面含有许多公用的属性,而URLTag定义了自己特有的属性,action,value,escapeAmp等,与配置文件相呼应。这里用到了Struts2程序中的一种组件模式, public Component getBean(ValueStack stack, HttpServletRequest req, HttpServletResponse res)。这里返回一个URL类的组件。而该URL组件实际上执行了自身标签特有的工作。

2.工作流程

标签的实现原理,实际上是继承了http servlet中可扩展的BodyTagSupport类。然后会依次执行以下方法:

根据上面分析,可以知道URL标签是依靠URLTag类实现的。我们找到了它继承的超类ComponentTagSupport组件,有doStartTag方法:

这里主要做了两件事:
(1)通过getBean()方法获取具体的组件Bean,这里是URL组件。然后将组件插入XWork容器中进行维护。
(2)对获取的URL组件中属性赋值。

紧接着执行component.start(pageContext.getOut());在这里看是执行URL组件的start方法。

对于具体的组件,会有自己特定自定义执行的过程,URL组件是执行渲染URL前的准备工作。

最后执行doEndTag()方法:

也是主要执行组件的自定义方法end(),在这个方法中,真正有对标签的渲染内容。

关键流程就是以上说明的方式,接着就在doStartTag方法开始对标签流程进行单步调试。

0x02 工作流程调试

在StartTag()方法中下断点,可以清楚的看到取出URL组件并对其属性赋值的过程。

然后在准备工作做完之后,我们跳过中间过程,并且直接进入到URL的end()方法中实现渲染的过程。
urlRenderer.renderUrl(writer, urlProvider);
该方法就开始对<s:url var="url" action="hello" includeParams="all"/>这句标签语句进行url链接生成。具体实现可以追踪到urlComponent.determineActionURL方法:

然后进入DefaultUrlHelper类,使用buildUrl方法,生成链接。生成的URL方法如下:

生成了链接URL字符串后,将生成的result放入page上下文和request Servlet上下文中。

然后我们就顺利的将处理好的URL放入request中,然后供标签调用。同样进入到了doStartTag()流程。

最后进入到了Anchor组件的end()方法。并使用FreemarkerTemplateEngine渲染引擎的renderTemplate(),通过定义的模板(默认.ftl文件)页面的渲染操作。