Запретить добавление суффикса к ресурсам при загрузке страницы

У меня есть приложение JSF2, работающее и работающее без проблем. Проблема, с которой я сталкиваюсь в JSF, связана с комплектом ресурсов. Все ресурсы .xhtml суффиксом .xhtml . Таким образом main.css становится main.css.xhtml при загрузке в браузере. Я хотел бы иметь его, поэтому .xhtml не используется для ресурсов (не обращайте внимания на сами страницы).

Есть ли способ, которым мы не можем иметь .xhtml добавленного к ресурсам?

В идеале я не должен был бы менять внутреннюю работу сайта. Я перечислил идеи ниже, но я должен сказать, что мне это не очень нравится. Надеяться на решение где-нибудь?

Я использую майорра v.2.1.17 на Glassfish 3.1.2.2.

Текущий уровень загрузки сервлетов, как в web.xml (обновлено)

  Faces Servlet javax.faces.webapp.FacesServlet 1   Faces Servlet *.xhtml   Faces Servlet /javax.faces.resource/*  

Почему эти вопросы отличаются от других

  • Ресурсы JSF 2 с CDN? , Я не хочу размещать свои ресурсы на CDN, но для того, чтобы мои ресурсы оставались на моем сервере, но были перенесены на CDN.
  • Измените префикс /javax.faces.resource URL-адресов ресурсов . Я не хочу менять префикс. Я хочу только изменить суффикс. Я бы хотел, чтобы чтобы стать: БЕЗ расширения .xhtml .
  • Изменение префикса JSF для преобразования суффикса заставляет меня повторно отображать на фоновых изображениях CSS . Поскольку у меня нет проблем с загрузкой ресурсов. Сайт работает, мы просто с трудом меняем веб-страницу с ресурса (поскольку мы смотрим только на расширение).

аргументация

Конечно, вы можете спросить меня, зачем мне это нужно. Ну, мы направляем наше заявление на обслуживание в CDN Akamai.

Проблема, связанная с интеграцией сайта, заключается в том, что мы пытаемся кэшировать статический контент на пограничных серверах. Это делается путем сопоставления расширений файлов (например: .js, .doc, .png, css и т. Д.). Мы не можем сопоставить xhtml потому что это будет кэшировать все страницы, а также статический контент. Это может вызвать проблемы с сеансами и т. Д.

Попытка решения

В соответствии с ответом BalusC я применил обработчик ресурсов, как было предложено. Я не буду переписывать код здесь, так как он находится в ответе ниже.

Однако при загрузке составных компонентов возникает ошибка. Я получаю ошибку как таковую:

 WARNING: StandardWrapperValve[Faces Servlet]: PWC1406: Servlet.service() for servlet Faces Servlet threw exception java.lang.NullPointerException at com.sun.faces.application.ApplicationImpl.createComponent(ApplicationImpl.java:975) at com.sun.faces.facelets.tag.jsf.CompositeComponentTagHandler.createComponent(CompositeComponentTagHandler.java:162) at com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.createComponent(ComponentTagHandlerDelegateImpl.java:494) at com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:169) ... 

Композитный компонент загружен правильно, потому что, если я «отменил регистрацию» нового ResourceHandler мы только что создали, он будет загружен. Трассировка стека приводит меня к мысли, что он пытается найти этот компонент в classе java, вместо того, чтобы находить его в ресурсах. Согласно grepcode это будет на последней строке (975), где происходит ошибка:

 String packageName = componentResource.getLibraryName(); String className = componentResource.getResourceName(); className = packageName + '.' + className.substring(0, className.lastIndexOf('.')); 

Это означает, что resourceName , aka className является null поскольку ошибка, которую я получаю, это java.lang.NullPointerException . Я не могу понять, как / где ResourceHandler называется vis-a-vis для составного компонента. Любая помощь в выяснении этой последней проблемы?

Это можно выполнить с помощью специального ResourceHandler который возвращает в createResource() Resource который, в свою очередь, возвращает «unmapped» URL-адрес Resource#getRequestPath() . Вам нужно только добавить префикс ресурсов JSF по умолчанию /javax.faces.resource/* в список отображения FacesServlet , чтобы в любом случае его запустить.

Кроме того, вам необходимо переопределить isResourceRequest() чтобы проверить, начинается ли URL-адрес с префикса ресурсов JSF, а также handleResourceRequest() для поиска и streamа соответствующего ресурса.

Все это должно сделать следующее:

 public class UnmappedResourceHandler extends ResourceHandlerWrapper { private ResourceHandler wrapped; public UnmappedResourceHandler(ResourceHandler wrapped) { this.wrapped = wrapped; } @Override public Resource createResource(final String resourceName, final String libraryName) { final Resource resource = super.createResource(resourceName, libraryName); if (resource == null) { return null; } return new ResourceWrapper() { @Override public String getRequestPath() { ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext(); String mapping = externalContext.getRequestServletPath(); if (externalContext.getRequestPathInfo() == null) { mapping = mapping.substring(mapping.lastIndexOf('.')); } String path = super.getRequestPath(); if (mapping.charAt(0) == '/') { return path.replaceFirst(mapping, ""); } else if (path.contains("?")) { return path.replace(mapping + "?", "?"); } else { return path.substring(0, path.length() - mapping.length()); } } @Override // Necessary because this is missing in ResourceWrapper (will be fixed in JSF 2.2). public String getResourceName() { return resource.getResourceName(); } @Override // Necessary because this is missing in ResourceWrapper (will be fixed in JSF 2.2). public String getLibraryName() { return resource.getLibraryName(); } @Override // Necessary because this is missing in ResourceWrapper (will be fixed in JSF 2.2). public String getContentType() { return resource.getContentType(); } @Override public Resource getWrapped() { return resource; } }; } @Override public boolean isResourceRequest(FacesContext context) { return ResourceHandler.RESOURCE_IDENTIFIER.equals(context.getExternalContext().getRequestServletPath()); } @Override public void handleResourceRequest(FacesContext context) throws IOException { ExternalContext externalContext = context.getExternalContext(); String resourceName = externalContext.getRequestPathInfo(); String libraryName = externalContext.getRequestParameterMap().get("ln"); Resource resource = context.getApplication().getResourceHandler().createResource(resourceName, libraryName); if (resource == null) { super.handleResourceRequest(context); return; } if (!resource.userAgentNeedsUpdate(context)) { externalContext.setResponseStatus(HttpServletResponse.SC_NOT_MODIFIED); return; } externalContext.setResponseContentType(resource.getContentType()); for (Entry header : resource.getResponseHeaders().entrySet()) { externalContext.setResponseHeader(header.getKey(), header.getValue()); } ReadableByteChannel input = null; WritableByteChannel output = null; try { input = Channels.newChannel(resource.getInputStream()); output = Channels.newChannel(externalContext.getResponseOutputStream()); for (ByteBuffer buffer = ByteBuffer.allocateDirect(10240); input.read(buffer) != -1; buffer.clear()) { output.write((ByteBuffer) buffer.flip()); } } finally { if (output != null) try { output.close(); } catch (IOException ignore) {} if (input != null) try { input.close(); } catch (IOException ignore) {} } } @Override public ResourceHandler getWrapped() { return wrapped; } } 

Зарегистрируйте его в faces-config.xml следующим образом:

  com.example.UnmappedResourceHandler  

Расширьте FacesServlet URL FacesServlet с помощью ResourceHandler.RESOURCE_IDENTIFIER :

  facesServlet *.xhtml /javax.faces.resource/*  

Вы могли бы взглянуть на Rewrite . Rewrite позволяет изменять URL-адреса, которые отображаются на странице, и изменять их любым способом. Вы можете сделать что-то подобное, чтобы добавить CDN на свой сайт:

 .addRule(CDN.relocate("{p}foo-{version}.css") .where("p").matches(".*") .where("version").matches(".*") .to("http://mycdn.com/foo-{version}.css")); 

Я думаю, что вам нужно будет легко выполнить свое требование с помощью Rewrite.

Посмотрите примерные конфигурации, чтобы узнать об особенностях перезаписи.

  • Как ссылаться на ресурс изображений JSF как URL-адрес фонового изображения CSS
  • Проверка подлинности электронной почты с использованием регулярного выражения в JSF 2 / PrimeFaces
  • действие вызывается только при втором щелчке
  • Переадресация авторизации при истечении срока действия сеанса не работает при отправке формы JSF, страница остается той же
  • commandButton / commandLink / ajax action / listener метод не вызывается или входное значение не установлено / обновлено
  • JSF + PrimeFaces: атрибут `update` не обновляет компонент
  • Связывание компонента JSF без свойства bean
  • Как использовать значения enums в f: selectItem (s)
  • Миграция с JSF 1.2 на JSF 2.0
  • com.sun.faces.numberOfViewsInSession vs com.sun.faces.numberOfLogicalViews
  • JSF возвращает пустую / непараметрированную страницу с открытым / исходным источником XHTML / XML / EL вместо вывода HTML-вывода
  • Давайте будем гением компьютера.