文档章节

sitemesh3 源码分析

big-hero
 big-hero
发布于 2012/03/09 12:51
字数 1225
阅读 1818
收藏 6
点赞 0
评论 2

sitemesh3是一个页面布局框架,可以是你的页面无缝的嵌入到一个整体页面中,从而是你的页面看起来风格是一致的,所有的一切从这里开始

ConfigurableSiteMeshFilter

public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
configProperties = getConfigProperties(filterConfig);
autoReload = getAutoReload();
logger.config("Auto reloading " + (autoReload ? "enabled" : "disabled"));

synchronized (configLock) {
deployNewFilter(setup());
}
initialized = true;
}

public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
if (!initialized) {
throw new ServletException(getClass().getName() + ".init(FilterConfig) was not called");
}
reloadIfNecessary();
filter.doFilter(servletRequest, servletResponse, filterChain);
}

sitemesh3是从该filter开始的,首先看init(),了解它初始化过程

我们看到configProperties = getConfigProperties(filterConfig);,是filter的配置信息,autoReload = getAutoReload();  查看配置文件是否需要自动重加载,默认是开启的。从后边可以知道它是通过对比sitemesh3.xml的最后修改时间来确定是不是需要加载的

这些只是准备工作,关键点在 deployNewFilter(setup()); ,也就是setup方法中

setup会创建一个filter,当执行到doFilter() ,内部实际执行的就是filter.doFilter(),到这里就可以肯定所有核心内容都在这个filter中,包括init和filter的过程,首先我们看init的过程,了解它都需要那些东西,然后再看doFilter中的内容,来决定我们怎么改进它。

protected Filter setup() throws ServletException {
ObjectFactory objectFactory = getObjectFactory();
SiteMeshFilterBuilder builder = new SiteMeshFilterBuilder();

new PropertiesFilterConfigurator(objectFactory, configProperties)
.configureFilter(builder);

new XmlFilterConfigurator(getObjectFactory(),
loadConfigXml(filterConfig, getConfigFileName()))
.configureFilter(builder);

applyCustomConfiguration(builder);

return builder.create();
}

一行一行的来讲ObjectFactory里面其实只有一行代码 return class.forName(className) ,就是为类生成对象,同时隔离到那些exception。

builder 这个类很重要,所有的配置信息都会存到里面,PropertiesFilterConfigurator 这行是将web.xml 中sitemeshfilter中的配置信息,存放到builder中

下面一行是将sitemesh3.xml中的配置信息,存放到builder中。

applyCustomConfiguration(builder);这行是为了通过java编码的方式来配置filter

配置信息有 exclude, decorate, minetype,content-processor,tag-rule-bundle

exclude 是不需要装饰,decorate是需要装饰的, minetype 是默认返回的页面类型, content-processor 是自定义的页面内容处理器,tag-rule-bundle 是自定义的标签,如<sitemesh:write/>等。

这里就可以看清楚sitemesh配置有三种方式 1,filter,2,sitemesh.xml, 3 java硬编码 ,混合使用的话,优先级从搞到低

下面我们去详细看看builder中有什么东西

Filter create() {
return new SiteMeshFilter(
getSelector(),
getContentProcessor(),
getDecoratorSelector());
}

看到没有一个热乎的filter出炉了, 用到了builder的三个属性, selector 选择器,contentProcessor 内容处理器,decoratorSelector 装饰选择器
我们继续深入:selector 是关于mineType决定是否拦截 , contentProcessor 是解析标签的 ,decoratorSelector 是关于装饰页面和被装饰页面的关系

好了,初始化过程基本就看完了,接下来就到正餐时间了,从上面我们没有看到更多的默认配置信息, 下一步就是这里filter.doFilter() ,等把这个过程理完了,然后再把代码通读一遍就能明白了

SiteMeshFilter.class
FilterConfig filterConfig = getFilterConfig();
if (filterConfig == null) {
// TODO: Is this really necessary? Can we survive without init() being called?
throw new ServletException(getClass().getName() + ".init() has not been called.");
}

HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
ServletContext servletContext = filterConfig.getServletContext();

if (!selector.shouldBufferForRequest(request)) {
// Optimization: If the content doesn't need to be buffered,
// skip the rest of this filter.
filterChain.doFilter(request, response);
return;
}

if (containerTweaks.shouldAutoCreateSession()) {
// Some containers (such as Tomcat 4) will not allow sessions
// to be created in the decorator. (i.e after the
// response has been committed).
request.getSession(true);
}

try {

// The main work.
bufferAndPostProcess(filterChain, request, response, selector);

} catch (IllegalStateException e) {
// Some containers (such as WebLogic) throw an IllegalStateException when an error page is served.
// It may be ok to ignore this. However, for safety it is propegated if possible.
if (!containerTweaks.shouldIgnoreIllegalStateExceptionOnErrorPage()) {
throw e;
}
} catch (RuntimeException e) {
if (containerTweaks.shouldLogUnhandledExceptions()) {
// Some containers (such as Tomcat 4) swallow RuntimeExceptions in filters.
servletContext.log("Unhandled exception occurred whilst decorating page", e);
}
throw e;
}

FilterConfig filterConfig = getFilterConfig(); 还记得这是什么时候注入的吗
!selector.shouldBufferForRequest(request) 初步判断: 是否已经呗sitemesh filter拦截过了, 是否不需要装饰
if (containerTweaks.shouldAutoCreateSession()) { 是否返回false, 是为适应tomcat4 写的
接下来看 关键部分 bufferAndPostProcess ,前面几行可以不用看 关键在于:

。。。。
filterChain.doFilter(wrapRequest(request), responseBuffer);
CharBuffer buffer = responseBuffer.getBuffer();

// If content was buffered, post-process it.
boolean processed = false;
if (buffer != null && !responseBuffer.bufferingWasDisabled()) {
processed = postProcess(responseBuffer.getContentType(), buffer, request, response, metaData);
}

if (!response.isCommitted()) {
responseBuffer.preCommit();
}

// If no decoratoes applied, and we have some buffered content, write the original.
if (buffer != null && !processed) {
writeOriginal(response, buffer, responseBuffer);
}

省略的几行是封装response,以便得到返回的html内容,还有就是控制response 的状态 如 if_modified_since 等
buffer是 返回的页面内容,已经被web容器解析过了。
在postProcess 开始进行装饰,如果没有成功就就buffer直接写入到response中
看postProcess 方法:

WebAppContext context = createContext(contentType, request, response, metaData);
Content content = contentProcessor.build(buffer, context);
if (content == null) {
return false;
}

String[] decoratorPaths = decoratorSelector.selectDecoratorPaths(content, context);
for (String decoratorPath : decoratorPaths) {
content = context.decorate(decoratorPath, content);
}

if (content == null) {
return false;
}

content.getData().writeValueTo(response.getWriter());
return true;

首先用rule规则将内容解析一遍,再找到要装饰的页面,然后用dispatch去解析,取得内容后,用context将被装饰页面和装饰页面一起解析
接下来我们着重看看一下 contentProccesor.build() 和 context.decorate() 和 context.build() 即可

就先到这里吧,自己一边看一边写挺累的

© 著作权归作者所有

共有 人打赏支持
big-hero

big-hero

粉丝 72
博文 27
码字总数 12032
作品 1
海淀
程序员
加载中

评论(2)

hemingwang0902
hemingwang0902
分析得比较深入,很有参考价值
Hartwell
Hartwell
很不错,参考了!
SpringMVC整合sitemesh3后无法POST

从新整理一下: 问题描述: SpringMVC中有一个方法被定义为 method= RequestMethod.POST, 详细代码如下 @RequestMapping(value="/testpost", method=RequestMethod.POST)public ModelAndView......

Nesson
2013/04/10
3.2K
2
sitemesh3 但输出的html总是被截断,不知道是否为content-length问题,求助高手?

各位大牛,我用的sitemesh3 + springmvc + mybatis + shiro,按官方3.0配置可执行,但输出的页面中body中的内容总是只输出一部分就截断了,不知道是否是sitemesh3源码中对content-length计算...

binux
2016/06/28
403
4
让Sitemesh3支持渲染错误页面

Sitemesh 3 一直让我蛮困扰的是不能把那些error页面也给渲染到框架页中,查询源码发现是在 org.sitemesh.webapp.contentfilter.BasicSelector.BasicSelector(boolean, String...) 这个类里面...

郁也风
2013/05/17
0
0
关于 sitemesh3 性能问题

谁做过sitemesh3的性能测试。sitemesh3性能怎么样?大家都用哪个布局页面的?

Mr.CT
2012/02/06
4.8K
6
Struts2结合sitemesh3制作网站母版页面

上一篇文章介绍了sitemesh3的使用,这篇文章来介绍如何结合struts2来配置和使用sitemesh,具体的如何使用sitemesh3我就不讲解了,这个你们可以看看我的上一篇博客。 首先你要添加struts和sit...

awbeci
2014/08/04
0
0
sitemesh3折磨我两天的问题

sitemesh3可不可以定义个name或者body啊, 比如我把A.jsp和B.jsp两个页面都定义在main.jsp里面 可不可以在main.jsp里面 左面显示A.jsp右边显示B.jsp 也就是说sitemesh3可以定义id或者name吗 ...

很纠结
2012/03/06
4.4K
8
sitemesh3 简单使用

sitemesh3 是使用filter安装装饰器模式对请求返回的内容进行装饰。 demo.html decorator.html 在web.xml中使用sitemesh的filter 然后在配置sitemesh3.xml,这个是sitemesh3的配置文件在/WEB-...

独钓渔
2016/12/22
42
0
sitemesh3 中怎么把某个tag的内容放置到父页面的指定位置?

sitemesh3默认只提供了title、head、body几个tag可以write到父页面的指定位置,不过我这有个需求想把某些tag(例如自定义的...)的内容扔到父页面的指定位置。 说说这个需求的场景吧,我们一...

郁也风
2012/06/06
2.8K
1
Sitemesh3中增加自定义tag

S3相比S2感觉舒服很多,用起来确实比传统的include方便,例如之前有个项目用了之后,切换布局什么的很省事,只需要调整一下框架页面就ok了,如果是include的话就费劲了。 不过S3预定义的只有...

郁也风
2012/12/04
0
3
关于前端使用SiteMesh的一些介绍

Overview 在网站开发的过程中,通常一个网站会有一个整体的风格,页面都有很多共同的菜单,横栏的底部信息。以前我们会采用标签在每个页面中来不断的包含各种, , and ,现在,在的帮助下,我...

facula
06/15
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

代码生成利器:IDEA 强大的 Live Templates

代码生成利器:IDEA 强大的 Live Templates

qwfys
16分钟前
1
0
spring boot使用通用mapper(tk.mapper) ,id自增和回显等问题

最近项目使用到tk.mapper设置id自增,数据库是mysql。在使用通用mapper主键生成过程中有一些问题,在总结一下。 1、UUID生成方式-字符串主键 在主键上增加注解 @Id @GeneratedValue...

北岩
19分钟前
0
0
告警系统邮件引擎、运行告警系统

告警系统邮件引擎 cd mail vim mail.py #!/usr/bin/env python#-*- coding: UTF-8 -*-import os,sysreload(sys)sys.setdefaultencoding('utf8')import getoptimport smtplibfr......

Zhouliang6
22分钟前
0
0
日常运维--rsync同步工具

rsync命令是一个远程数据同步工具,可通过LAN/WAN快速同步多台主机间的文件。rsync使用所谓的“rsync算法”来使本地和远程两个主机之间的文件达到同步,这个算法只传送两个文件的不同部分,而...

chencheng-linux
26分钟前
1
0
Java工具类—随机数

Java中常用的生成随机数有Math.random()方法及java.util.Random类.但他们生成的随机数都是伪随机的. Math.radom()方法 在jdk1.8的Math类中可以看到,Math.random()方法实际上就是调用Random类...

PrivateO2
38分钟前
1
0
关于java内存模型、并发编程的好文

Java并发编程:volatile关键字解析    volatile这个关键字可能很多朋友都听说过,或许也都用过。在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果。在...

DannyCoder
昨天
0
0
dubbo @Reference retries 重试次数 一个坑

在代码一中设置 成retries=0,也就是调用超时不用重试,结果DEBUG的时候总是重试,不是0吗,0就不用重试啊。为什么还是调用了多次呢? 结果在网上看到 这篇文章才明白 https://www.cnblogs....

奋斗的小牛
昨天
0
0
数据结构与算法3

要抓紧喽~~~~~~~放羊的孩纸回来喽 LowArray类和LowArrayApp类 程序将一个普通的Java数组封装在LowArray类中。类中的数组隐藏了起来,它是私有的,所以只有类自己的方法才能访问他。 LowArray...

沉迷于编程的小菜菜
昨天
0
0
spring boot应用测试框架介绍

一、spring boot应用测试存在的问题 官方提供的测试框架spring-boot-test-starter,虽然提供了很多功能(junit、spring test、assertj、hamcrest、mockito、jsonassert、jsonpath),但是在数...

yangjianzhou
昨天
0
0
rsync工具介绍/rsync通过ssh同步

rsync工具介绍 数据备份是必不可少,在Linux系统下数据备份的工具很多,其中重点介绍就是rsync工具,rsync不仅可以远程同步数据,还可以本地同步数据,且不会覆盖以前的数据在已经存在的数据...

Hi_Yolks
昨天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部