7

私は今日、Freemarker から Tiles2 + Freemarker に移行するのに苦労していました。

私の freemarker テンプレートは、spring.ftl からのマクロを使用します。

web.xml で fremarker サーブレットを提供すると、私のモデルは freemarker に表示されますが、Spring FreemarkerView がそれを担当するため、特定の Spring 変数は (当然のことながら) モデルに取り込まれません。

特定の URL (「/tpl/*」など) に対して個別の DispatcherServlet を構成し、そのサーブレットのデフォルトのビュー リゾルバーとして freemarker リゾルバーを構成し、UrlFilenameViewController をデフォルトのコントローラーとして提供すると、特別なスプリング変数がモデルに取り込まれますが、私自身のモデルは非表示: リクエスト属性としてバインドされています。${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);
    }

しかし、このソリューションもやや臭いです。ビジネス コントローラーのモデルに何かを追加する場合は、ここに追加する必要があります。

私の問題に対するエレガントな解決策はありますか?

4

1 に答える 1

1

2 つのプロジェクトで同じ問題を解決したことを覚えています。あなたの 2 番目のアプローチはほぼ正しい ( 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());
        }
    }
}

春に両方を登録します。

<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"/>

動作するはずです。

于 2013-02-08T21:54:42.517 に答える