SiteMesh3原理和SpringMVC + FreeMarker + SiteMesh3問題


先附上一個SiteMesh3+FreeMarker+SpringMVC例子http://files.cnblogs.com/adaikiss/sitemesh3_freemarker_springmvc.zip

下載后解壓,本地環境變量要有MAVEN,CMD進入工程目錄直接運行mvn jetty:run

 

昨天花了一天時間來跟蹤調試springmvc, freemarker, sitemesh3, 終於弄明白了大概的原理,最后解決了sitemesh中文(UTF-8)亂碼,ftl裝飾頁不被渲染的問題。

sitemesh3是通過一個filter來對response進行攔截處理,在response提交之前,它會把response流里的數據備份起來,清空流,然后用request.getRequestDispatcher(裝飾頁URI).forward()來取得渲染后的裝飾頁,然后再把裝飾頁里的標簽替換成之前備份的對應內容。

也就是說sitemesh不關心你的頁面是如何生成的,它只是將兩者拼接起來,不管你用的是JSP,Volocity, FreeMarker 還是 SpringMVC, Struts, wicket。

這樣一來你就可以靈活地控制頁面的生成方式。你可以把sitemesh3當成一個中間瀏覽器,他使用用戶瀏覽器發送過來的request對象發送了兩次(或以上)請求,第一次是原來的請求, 第二次是對裝飾頁面的請求,然后把這兩個請求結果拼接起來返回給用戶瀏覽器。

看到這里,裝飾頁如果是FTL就不被渲染的問題也就有了解決方法了。只要自己寫一個過濾器對.ftl的請求用freemarker渲染一遍就可以了。由於我使用的是springmvc + freemarker,因此我直接拿springmvc來渲染FTL文件了,這樣可以像被裝飾頁一樣方便地使用spring的宏和其他一些對象。下面是我的filter

public class FreemarkerFilter implements Filter {

    private Locale locale;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        String localeStr = filterConfig.getInitParameter("locale");
        if(StringUtils.isNotBlank(localeStr)){
            locale = new Locale(localeStr);
        }else {
            locale = Locale.getDefault();
        }
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        try {
            HttpServletRequest req = (HttpServletRequest)request;
            HttpServletResponse res = (HttpServletResponse)response;
            String name = req.getRequestURI();
            name = name.substring(1, name.lastIndexOf(".ftl"));
            FreeMarkerViewResolver viewResolver = SpringContextHolder.getBean(FreeMarkerViewResolver.class);
            View view = viewResolver.resolveViewName(name, locale);
 @SuppressWarnings("unchecked") Map<String, Object> model = (Map<String, Object>) request.getAttribute(ViewRendererServlet.MODEL_ATTRIBUTE);
            view.render(null, req, res);
        } catch (Exception e) {
            throw new ServletException(e);
        }
    }

    @Override
    public void destroy() {
        // TODO Auto-generated method stub
        
    }
    
}

在這里,我是把SpringMVC對被裝飾頁處理時生成的model傳到了裝飾頁。裝飾頁和原來被include進來的頁面差不多,一般裝飾頁可能不需要使用被裝飾頁中的model, 可以把SuppressWarnings注解下面那行注釋掉,下面傳null過去。

在web.xml里加上過濾器配置:

<filter>
      <filter-name>freemarkerFilter</filter-name>
      <filter-class>org.adaikiss.kay.web.FreemarkerFilter</filter-class>
  </filter>
  <filter-mapping>
      <filter-name>freemarkerFilter</filter-name>
      <url-pattern>*.ftl</url-pattern>
      <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
  </filter-mapping>

 

這樣一來由sitemesh forward的請求就能被攔截並渲染。當然,你也可以把裝飾頁的后綴改成.des,url-pattern要同步改。

 

關於中文亂碼的問題,在跟蹤代碼的時候發現對於沒有contentType的view,SpringMVC會使用默認的contentType:AbstractTemplateView.DEFAULT_CONTENT_TYPE,即

"text/html;charset=ISO-8859-1",view 中可以設置這個屬性,不過我的配置里沒有定義view,還好ViewResolver里也可以設置,在springmvc配置文件里加上contentType屬性即可。

<bean id="viewResolver"
class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="contentType" value="text/html; charset=UTF-8"/>

...

</bean>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM