Spring + Tiles2 + Freemarker - интегрировать с помощью сервлета Freemarker или с помощью Spring FreeMarkerViewResolver? - PullRequest
7 голосов
/ 24 октября 2008

Я боролся сегодня, пытаясь перейти с Freemarker на Tiles2 + Freemarker.

В моих шаблонах freemarker используются макросы, которые взяты из spring.ftl.

Если я предоставлю сервлет fremarker в web.xml, моя модель будет видима для freemarker, но конкретные пружинные переменные (естественно) не будут введены в модель, так как за это отвечает источник FreemarkerView.

Если я настрою отдельный DispatcherServlet для определенного URL-адреса (скажем, "/ tpl / *") и сконфигурирую распознаватель freemarker в качестве распознавателя представления по умолчанию для этого сервлета и предоставлю UrlFilenameViewController в качестве контроллера по умолчанию, специальные пружинные переменные заполняются для модели, но мои собственная модель не видна: она связана как атрибут запроса. Я могу получить доступ к своей модели через $ {Request.mymodel.myvar}, но таким образом мне нужно изменить все мои шаблоны свободных маркеров, и я вижу что-то вонючее в идее.

Теперь моим решением было расширить 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);
    }

Но и это решение несколько вонючее - если я добавлю что-то к модели в своих бизнес-контроллерах, я должен добавить это сюда.

Есть ли элегантное решение для моей проблемы?

1 Ответ

1 голос
/ 09 февраля 2013

Помню, я решил одну и ту же проблему в двух проектах. Ваш второй подход почти верен (FreeMarkerViewResolver), но если я правильно помню, мне также пришлось расширить с FreeMarkerView и TilesView, чтобы явно соединить обе модели вместе.

Пользовательский вид плиток:

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

Должно работать.

...