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

Браузер назад + viewcope beans

Проблема с: Что происходит при нажатии кнопки "Назад браузера" → открывается страница, чья viewcoped-managedbean уже уничтожена → отправить запрос с commandButton с этой страницы с выбором селекторной записи?

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

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

Итак, здесь сценарий успеха, все beans просматриваются beans:

  • GET page1.xhtml → page1Bean создан, запрашивает данные и т.д. в @PostConstruct
  • проверьте/выберите несколько записей из данных, нажмите кнопку процесса
  • page1Bean process method хранит выбранные записи в объекте flash и перенаправляет на страницу2.xhtml
  • page1Bean destroy, page2Bean created, и в методе прослушивания preRenderView извлекает выбранные записи из объекта flash и обрабатывает их
  • нажмите кнопку "перейти на главную страницу", чтобы перенаправить на страницу1.xhtml и page2Bean уничтожен, страница1Bean снова создана.
  • цикл от 2 до 5 все еще выполним

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

  • GET page1.xhtml → page1Bean создан, запрашивает данные и т.д. в @PostConstruct
  • проверьте/выберите несколько записей из данных, нажмите кнопку процесса
  • page1Bean process method хранит выбранные записи в объекте flash и перенаправляет на страницу2.xhtml
  • page1Bean destroy, page2Bean created, и в методе прослушивания preRenderView извлекает выбранные записи из объекта flash и обрабатывает их
  • нажмите кнопку браузера назад. 2Bean не уничтожен, страница1Bean не создается.
  • проверьте/выберите несколько записей из данных, нажмите кнопку процесса
  • выполняется метод page1Bean (странно, потому что страница1Bean должна быть уничтожена), но не может видеть сделанные записи и перенаправлять на page2.xhtml
  • page1Bean не уничтожается (нет выхода журнала), page2Bean не создается (поскольку он не был уничтожен), выполняет прослушиватель preRenderView, как обычно, но на этот раз никакие выбранные записи в объекте flash

Возможно ли иметь нормальный опыт (как будто без кнопки браузера) с viewcope- beans с помощью кнопки браузера?

Здесь моя зависимость:

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

Поделитесь своими идеями!

4b9b3361

Ответ 1

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

Есть два способа решить эту проблему:

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

    @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-адресом.

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

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

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

Ответ 2

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

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

@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>

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