Как использовать управление версиями JSF для ресурсов в jar

ПФ 3.5.10, Мохарра 2.1.21, омнифас 1.5

У меня есть библиотека JSF (только с файлами CSS). Эта библиотека находится в файле.jar. CSS будет включен в XHTML с <h:outputStylesheet library="mylib" name="css/mycss.css">,

В HTML это представляется следующим образом: localhost:8080/cms/javax.faces.resource/css/mycss.css.jsf?ln=mylib

CSS файл простых лиц отображается в: localhost:8080/cms/javax.faces.resource/primefaces.js.jsf?ln=primefaces&v=3.5.10

Обратите внимание на версию библиотеки (&3.5.10) в конце. Как я могу сделать то же самое? Должен ли я написать версию в Manifest.mf. Или как я могу использовать JSF-версии в JAR-файл?

3 ответа

Решение

К сожалению, это невозможно. Управление версиями библиотеки не поддерживается для ресурсов в JAR.

У вас есть в основном 2 варианта:

  1. Сделайте это простым и безобразным способом, включив время запуска сервера в виде строки запроса. Учитывая, что вы используете OmniFaces, вы можете использовать его встроенный #{startup} управляемый бин, ссылаясь на java.util.Date экземпляр в области применения:

    <h:outputStylesheet ... name="some.css?#{startup.time}" />
    <h:outputScript ... name="some.js?#{startup.time}" />
    

    Или, возможно, у вас уже есть версия переменной приложения.

    <h:outputStylesheet ... name="some.css?v=#{app.version}" />
    <h:outputScript ... name="some.js?v=#{app.version}" />
    

    Обновление: Несмотря на это, это не работает для <h:outputStylesheet>, Смотрите также: https://github.com/javaserverfaces/mojarra/issues/3945 или https://github.com/javaee/javaserverfaces-spec/issues/1395

    Это работает для <h:outputScript> однако, который имел очень похожий отчет об ошибках, который был реализован довольно скоро https://github.com/javaserverfaces/mojarra/issues/1216

  2. Сделайте так же, как PrimeFaces, создайте кастом ResourceHandler,

    public class MyVersionResourceHandler extends ResourceHandlerWrapper {
    
        private ResourceHandler wrapped;
    
        public MyVersionResourceHandler(ResourceHandler wrapped) {
            this.wrapped = wrapped;
        }
    
        @Override
        public Resource createResource(String resourceName) {
            return createResource(resourceName, null, null);
        }
    
        @Override
        public Resource createResource(String resourceName, String libraryName) {
            return createResource(resourceName, libraryName, null);
        }
    
        @Override
        public Resource createResource(String resourceName, String libraryName, String contentType) {
            final Resource resource = super.createResource(resourceName, libraryName, contentType);
    
            if (resource == null) {
                return null;
            }
    
            return new ResourceWrapper() {
    
                @Override
                public String getRequestPath() {
                    return super.getRequestPath() + "&v=1.0";
                }
    
                @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 ResourceHandler getWrapped() {
            return wrapped;
        }
    
    }
    

    Или, если вы уже используете OmniFaces, это можно сделать проще:

    public class YourVersionResourceHandler extends DefaultResourceHandler {
    
        public YourVersionResourceHandler(ResourceHandler wrapped) {
            super(wrapped);
        }
    
        @Override
        public Resource decorateResource(Resource resource) {
            if (resource == null || !"mylib".equals(resource.getLibraryName())) {
                return resource;
            }
    
            return new RemappedResource(resource, resource.getRequestPath() + "&v=1.0");
        }
    
    }
    

    В любом случае, чтобы запустить его, зарегистрируйте его как <resource-handler> в /META-INF/faces-config.xml из банки.

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

Вы также можете использовать версию своего проекта и добавить ее в качестве номера версии для своих файлов ресурсов. Это можно сделать с помощью maven-war-plugin, maven-war-plugin будет просматривать ваши страницы во время сборки и заменять определенные свойства.

В следующем примере показано, как настроить maven-war-plugin отфильтровать ресурсы вашего веб-приложения, чтобы добавить пользовательское свойство asset.version:

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" ...>
  ...

  <properties>
    <asset.version>${project.version}</asset.version>    
  </properties>

  ...

  <build>
    <plugins>
      ...

      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-war-plugin</artifactId>
        <version>2.3</version>
        <configuration>

          <nonFilteredFileExtensions>
            <nonFilteredFileExtension>gif</nonFilteredFileExtension>
            <nonFilteredFileExtension>ico</nonFilteredFileExtension>
            <nonFilteredFileExtension>jpg</nonFilteredFileExtension>
            <nonFilteredFileExtension>png</nonFilteredFileExtension>
            <nonFilteredFileExtension>pdf</nonFilteredFileExtension>
          </nonFilteredFileExtensions>

          <failOnMissingWebXml>false</failOnMissingWebXml>

          <webResources> 
            <webResource>
              <directory>${basedir}/src/main/webapp</directory> 
              <filtering>true</filtering> 
            </webResource>
          </webResources> 

        </configuration>
      </plugin>

      ...
    </plugins>
  </build>

</project>

asset.version свойство может быть использовано в вашем файле JSF.

Вот пример, протестированный с JSF 2.2:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html ...
      xmlns:jsf="http://xmlns.jcp.org/jsf">

...
<script jsf:name="js/libs/pure/pure-min.css?v=${project.version}" />

Результат (в моем случае) будет следующим:

<script type="text/javascript" src="/context-path/javax.faces.resource/js/libs/pure/pure-min.css.xhtml?v=1.0.15-SNAPSHOT"></script>

Ответ @Balusc сказал: "Ну, не ошибка, но провал и провал спецификации". Кажется, что ресурсы CSS, развернутые в библиотеках, не могут быть версионированы с помощью mojarra 2.2.14. Это правильно? Я пытался реализовать ваше решение с помощью пользовательского ResourceHandler, но ресурс, возвращаемый getWrapped(). CreateResource(resourceName, libraryName) всегда возвращает ноль. Кажется, что createResource() пытается найти ресурсы библиотеки (например, css/layout.css) с помощью пути /META-INF/resources/, но ему не хватает версии.

Чтобы обойти проблему, я переопределил метод createResource в пользовательском ResourceHandler, который расширяет Omnifaces DefaultResourceHandler для добавления префикса версии к resourceName

@Override
public Resource createResource(String resourceName, String libraryName) {
    if (libraryName != null && libraryName.equals(LIBRARY_NAME)) {
        if (!resourceName.startsWith(version)) {
            resourceName = version + "/"+resourceName;
        }
    }
    return super.createResource(resourceName, libraryName);
}

С этим обходным путем сгенерированная ссылка выглядит так

<link type="text/css" rel="stylesheet" href="/javax.faces.resource/1_0_3/css/layout.css?ln=common&amp;v=1_0_3"/>

для объявления outputStylesheet

<h:outputStylesheet library="common" name="css/layout.css" />

Я не уверен, что это лучший обходной путь.

Другие вопросы по тегам