Подтвердить что ты не робот

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

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

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

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

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

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

<servlet>
    <servlet-name>Faces Servlet</servlet-name>
    <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>/javax.faces.resource/*</url-pattern>
</servlet-mapping>

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

Рассуждение

Конечно, вы можете спросить меня, зачем мне это нужно. Ну, мы направляем наше приложение для обслуживания 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, который мы только что создали, он будет загружен. Трассировка стека приводит меня к мысли, что он пытается найти этот компонент в классе 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 для составного компонента. Любая помощь в выяснении этой последней проблемы?

4b9b3361

Ответ 1

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

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

Все со всеми, это должно делать:

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<String, String> 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 следующим образом:

<application>
    <resource-handler>com.example.UnmappedResourceHandler</resource-handler>
</application>

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

<servlet-mapping>
    <servlet-name>facesServlet</servlet-name>
    <url-pattern>*.xhtml</url-pattern>
    <url-pattern>/javax.faces.resource/*</url-pattern>
</servlet-mapping>

Ответ 2

Вы можете посмотреть 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.

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