【问题标题】:Spring + Tiles2 + Freemarker - integrate via Freemarker Servlet or via Spring's FreeMarkerViewResolver?Spring + Tiles2 + Freemarker - 通过 Freemarker Servlet 或 Spring 的 FreeMarkerViewResolver 集成?
【发布时间】:2008-10-24 14:55:04
【问题描述】:

我今天正在努力从 Freemarker 迁移到 Tiles2 + Freemarker。

我的 freemarker 模板使用来自 spring.ftl 的宏。

如果我在 web.xml 中提供一个 fremarker servlet,我的模型对 freemarker 是可见的,但特定的 spring 变量(自然)不会填充到模型中,因为 springs FreemarkerView 负责。

如果我为特定的 url(比如“/tpl/*”)配置一个单独的 DispatcherServlet,并将 freemarker 解析器配置为该 servlet 的默认视图解析器,并提供 UrlFilenameViewController 作为默认控制器,则特殊的 spring 变量确实会填充到模型中,但我的自己的模型不可见:它被绑定为请求属性。我可以通过 ${Request.mymodel.myvar} 访问我的模型,但这样我必须更改我所有的 freemarker 模板,并且我发现这个想法有些异味。

现在我的解决方案是扩展 UrlFilenameViewController 并将我的模型从请求添加到 ModelAndView:

protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)  {
        ModelAndView mav = super.handleRequestInternal(request, response);

        HashMap<String, Object> map = new HashMap<String, Object>();

        Enumeration<String> attributes = request.getAttributeNames();

        while(attributes.hasMoreElements()) {
            String attribute = attributes.nextElement();

            if("model".equals(attribute)) {
                logger.debug("FreemarkerViewController.handleRequestInternal: putting attribute to model: " + attribute + "=" + request.getAttribute(attribute));
                map.put(attribute, request.getAttribute(attribute));
            }
        }
        logger.debug("FreemarkerViewController.handleRequestInternal: VIEW: " + mav.getViewName());
        return new ModelAndView(mav.getViewName(), map);
    }

但是这个解决方案也有点臭——如果我在我的业务控制器的模型中添加一些东西,我必须在这里添加它。

我的问题有什么优雅的解决方案吗?

【问题讨论】:

  • 你有没有找到更好的解决方案?
  • 我正在使用 freemarker servlet 和 spring taglibs - 他们通过特殊的 spring freemarker 宏处理我使用的所有内容。

标签: java spring tiles freemarker tiles2


【解决方案1】:

我记得我在两个项目中解决了同样的问题。 您的第二种方法几乎是正确的 (FreeMarkerViewResolver),但如果我没记错的话,我还必须从 FreeMarkerViewTilesView 扩展以明确地将两个模型连接在一起。

自定义图块视图:

public class CustomTilesView extends TilesView {

    @Override
    protected void exposeModelAsRequestAttributes(Map model, HttpServletRequest request) {
        request.setAttribute(CustomFreeMarkerView.MODEL_KEY, model);
    }
}

自定义 FreeMarker 视图:

public class CustomFreeMarkerView extends FreeMarkerView {

    public static final String MODEL_KEY = FreeMarkerView.class.getName() + ".MODEL";

    @Override
    protected void exposeHelpers(Map model, HttpServletRequest request) throws Exception {
        super.exposeHelpers(model, request);
        final Map savedModel = (Map) request.getAttribute(MODEL_KEY);
        if (savedModel != null) {
            mergeModels(model, savedModel);
        }
    }

    private void mergeModels(Map<String, Object> targetModel, Map<String, Object> recipientModel) throws ServletException {
        for (Map.Entry<String, Object> entry : recipientModel.entrySet()) {
            String key = entry.getKey();
            if (targetModel.containsKey(key)) {
                throw new ServletException("Cannot merge models because of an existing model object of the same name: " + key);
            }
            targetModel.put(key, entry.getValue());
        }
    }
}

在 Spring 中同时注册:

<bean class="org.springframework.web.servlet.view.UrlBasedViewResolver"
      p:viewClass="com.my.CustomTilesView"
      p:contentType="text/html;charset=UTF-8"/>

<bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver"
      p:suffix=".ftl"
      p:exposeSpringMacroHelpers="true"
      p:viewClass="com.my.CustomFreeMarkerView"
      p:contentType="text/html;charset=UTF-8"/>

应该可以。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-07-29
    • 2013-07-21
    • 2015-09-24
    • 1970-01-01
    • 1970-01-01
    • 2010-09-18
    • 1970-01-01
    相关资源
    最近更新 更多