SiteMesh: изменение типа содержимого ответа - PullRequest
2 голосов
/ 23 февраля 2010

Я пытаюсь убедить декоратора SiteMesh изменить тип содержимого ответа, но без радости. Тип содержимого всегда совпадает с оформленным JSP, а не с декоратором.

Например, скажем, у меня есть JSP с заголовком

<%@ page contentType="application/xhtml+xml" %>

У меня также есть JSP декоратор SiteMesh, который определяет это:

<%@ page contentType="application/vnd.wap.xhtml+xml" %>

Я хочу, чтобы оформленный ответ имел тип mime декоратора (фактический тип MIME, используемый здесь, не важен, это просто для иллюстрации проблемы).

Исследование источника SiteMesh 2.4.1 показывает, что проблема заключается в классе ContentBufferingResponse, который отвечает за захват выходных данных цели. Это переопределяет метод setContentType(), записывая значение для последующего использования, но также вызывает super.setContentType(), эффективно передавая тип содержимого целевой JSP непосредственно в ответ. Как только это будет сделано, никакие уговоры не убедят ответ поступить иначе.

Так есть ли обходной путь для этого? Может ли тип содержимого целевой JSP подавляться и вместо этого извлекаться из декоратора?

Ответы [ 2 ]

1 голос
/ 15 апреля 2010

ContentBufferingResponse.setContentType вызовет вызов HttpServletResponseWrapper.setContentType. Позднее в ответ включается декоратор, использующий RequestDispatcher.include, который не может изменить код состояния или установить заголовки (любая попытка внести изменения игнорируется). Так что, по сути, после того, как вы установите тип контента, его игру окончено, вы не сможете его изменить.

Из того, что я вижу, метод SiteMeshFilter.obtainContent - единственное место, где создается экземпляр класса ContentBufferingResponse, поэтому SiteMeshFilter и ContentBufferingResponse - это места для поиска обходных путей.

Один из возможных обходных путей - перезаписать obtainContent в подклассе SiteMeshFilter и разрешить правильный метод во время выполнения с использованием полиморфизма. Есть только одна проблема: obtainContent помечен как приватный, поэтому полиморфизм не сработает. Чтобы вызвать другой метод obtainContent, вам придется перезаписать в фильтре намного больше, чем этот метод, и я боюсь, что в него будет включен сам метод doFilter.

Другим обходным решением было бы как-то вызвать другую версию метода setContentType, которая не вызывает super.setContentType с типом mime украшенной страницы. Но вы не можете изменить вызов на другой метод, поскольку в коде obtainContent мы создаем экземпляр ContentBufferingResponse, используя «new».

На этом этапе вы можете создать копию класса ContentBufferingResponse в своем проекте (с тем же объявлением пакета), в котором метод setContentType вызывает super.setContentType с нужным вам типом mime, а не типом mime. с оформленной страницы. Затем вы можете заставить сервер загружать ваш класс вместо оригинала, поиграв с classpath и убедившись, что ваш класс загружен раньше, чем тот, который находится в банке SiteMesh. Основной проблемой здесь будет управление между различными типами MIME, если у вас есть более одного декоратора (и я уверен, что у вас есть: D).

Третий (также некрасивый) обходной путь - просто взломать код SiteMesh и разобраться с ним (не уверен, что у вас возникнут проблемы с лицензией).

Так что, по моему мнению, если вы не захотите прибегнуть к каким-то уродливым временным решениям, вы не сможете изменить тип контента после его установки.

0 голосов
/ 22 февраля 2011

Напишите фильтр сервлетов, который применяется к вашей странице, переопределите setContentType(), чтобы не вызывать супер, и затем в декораторе вы можете установить тип содержимого на любой, какой вы захотите.

Для этого вам понадобится написать еще один фильтр сервлетов, но он должен быть довольно простым.

...