браузер обратно + видоискатель бобов - PullRequest
12 голосов
/ 09 ноября 2011

В чем проблема : что происходит при нажатии кнопки «Назад» в браузере -> открывает страницу, у которой viewscoped-managedbean уже уничтожено -> отправляет запрос из commandButton с этой страницы с помощьюgrid-record-selections?

Что я ожидаю : Связанный viewcope-managebean воссоздается, получает выборки grid-record-selection и обрабатывает их, как будто кнопка возврата браузераникогда не участвует.

Что я испытываю : Связанный viewcope-managebean НЕ воссоздан, не получает выборки записи сетки.Придется повторно ввести URL или F5 после нажатия на кнопку возврата в браузере, чтобы он снова работал правильно.

Итак, вот сценарий успеха , все bean-компоненты являются bean-объектами видимости:

  1. GET page1.xhtml -> page1Bean создан, запрос данных и т. Д. В @ PostConstruct
  2. отметьте / выберите несколько записей из таблицы данных, нажмите кнопку процесса
  3. page1Bean-процессМетод сохраняет выбранные записи во флэш-объекте и перенаправляет их на страницу page2.xhtml
  4. page1Bean уничтожен, создан page2Bean, а в методе прослушивания preRenderView извлекает выбранные записи из флэш-объекта и обрабатывает их
  5. нажмите кнопку «Перейти на главную страницу», чтобы перенаправить на page1.xhtml, и page2Bean уничтожен, page1Bean создан заново * цикл
  6. из номера 2 - 5 все еще выполним

Теперь, это ошибочный сценарий , включающий кнопку возврата браузера (различные вещи, начиная с # 6):

  1. GET page1.xhtml -> page1Bean создан, запрос данных и т. Д. В @ PostConstruct
  2. отметьте / выберите несколько записей из таблицы данных, нажмите кнопку процесса
  3. page1Bean-метод процесса сохраняет выбранные записи вфлэш-объект и перенаправить на страницу page2.xhtml
  4. page1Bean уничтожен, создан page2Bean и в методе прослушивания preRenderView извлекает выбранные записи из флэш-объекта и обрабатывает их
  5. нажмите кнопку браузера назад page2Bean не уничтожен, page1Bean не создан
  6. отметьте / выберите несколько записей из таблицы данных, нажмите кнопку процесса
  7. метод page1Bean выполняется (странно,потому что page1Bean должен был быть уничтожен), но не может видеть сделанные выборки записей и перенаправить на page2.xhtml
  8. page1Bean не уничтожается (без вывода журнала), page2Bean не создается (так как он не былуничтожено), выполняет прослушиватель preRenderView как обычно, но на этот раз нет выбранных записей.В объекте флэш-памяти

Возможно ли получить нормальный опыт (как без кнопки возврата браузера) с компонентами Viewcope с кнопкой возврата браузера?

Вот моя зависимость:

<dependency>
    <groupId>org.glassfish</groupId>
    <artifactId>javax.faces</artifactId>
    <version>2.1.3</version>
    <scope>compile</scope>
</dependency>

Пожалуйста, поделитесь своими идеями!

Ответы [ 2 ]

16 голосов
/ 09 ноября 2011

Похоже, что браузер обслуживал страницу из своего кэша вместо того, чтобы отправлять на сервер полноценный HTTP-запрос GET, в то время как для метода сохранения состояния JSF установлено значение server (по умолчанию).

Есть 2 способа решения этой проблемы:

  1. Скажите браузеру, чтобы он не кэшировал динамические страницы JSF. Вы можете сделать это с помощью фильтра .

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse res = (HttpServletResponse) response;
    
        if (!req.getRequestURI().startsWith(req.getContextPath() + ResourceHandler.RESOURCE_IDENTIFIER)) { // Skip JSF resources (CSS/JS/Images/etc)
            res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
            res.setHeader("Pragma", "no-cache"); // HTTP 1.0.
            res.setDateHeader("Expires", 0); // Proxies.
        }
    
        chain.doFilter(request, response);
    }
    

    Сопоставить фильтр с FacesServlet или его тем же шаблоном URL.

  2. Установите метод сохранения состояния JSF для клиента, чтобы все состояние просмотра сохранялось в скрытом поле формы, а не в сеансе на стороне сервера.

    <context-param>
        <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
        <param-value>client</param-value>
    </context-param>
    

Предпочтителен способ фильтрации.

0 голосов
/ 26 февраля 2014

Недостаток отключения кэша браузера на странице состоит в том, что пользователь увидит страницу с ошибкой браузера, если он использует браузер назад для перехода на предыдущую страницу.Таким образом, другое решение состоит в том, чтобы определить, приходит ли страница с сервера или из кэша браузера, используя javascript:

Сначала создайте простой компонент поддержки, который обслуживает уникальный идентификатор (в моем случае текущее системное время):

@Named("browserCacheController")
@RequestScoped
public class BrowserCacheController implements Serializable {
private static final long serialVersionUID = 1L;
/**
 * Returns a unique increasing id for each request
 * @return
 */
public long getCacheID() {
    return System.currentTimeMillis();
}   
}

Теперь вы можете проверить, обслуживается ли страница с сервера или браузера, и перенаправить пользователя, если текущая страница поступает из кэша браузера.См. Следующий код javascript, размещенный на странице jsf, который не должен кэшироваться браузером:

<script type="text/javascript">
    // check for latestCacheID
    if (!isValidCacheID(#{browserCacheController.cacheID})) {
        //redirect to some page
        document.location="#{facesContext.externalContext.requestContextPath}/index.jsf";
    }

    // test cacheID if it comes from the server....
    function isValidCacheID(currentCacheID) {
        if (!('localStorage' in window && window['localStorage'] !== null))
            return true; // old browsers not supported
        var latestCacheID=localStorage.getItem("org.imixs.latestCacheID");
        if (latestCacheID!=null && currentCacheID<=latestCacheID) {
            return false; // this was a cached browser page!
        }
        // set new id
        localStorage.setItem("org.imixs.latestCacheID", currentCacheID);
        return true;
    }
</script>

Сценарий также можно поместить в facelet, чтобы сделать код jsf более чистым.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...