Как ориентироваться в JSF? Как сделать так, чтобы URL отражал текущую страницу (а не предыдущую)

В настоящее время я изучаю JSF и был довольно удивлен и озадачен, когда понял, что всякий раз, когда мы используем <h:form> стандартное поведение JSF - всегда показывать мне URL предыдущей страницы в браузере, а не URL текущей страницы.

Я понимаю, что это связано с тем, что JSF всегда отправляет форму на одну и ту же страницу, а затем просто отображает любую страницу, которую контроллер возвращает ее браузеру, который не знает, что расположение страницы изменилось.

Кажется, что JSF существует достаточно долго, поэтому должен быть чистый, надежный способ справиться с этим. Если да, не могли бы вы поделиться?

Я нашел различные обходные пути, но, к сожалению, ничего похожего на реальное солидное решение.

  • Просто примите, что URL вводит в заблуждение.
  • присоединять "?faces-redirect=true" к возвращаемому значению действия каждого компонента, а затем
    • выяснить, как заменить @RequestScoped с чем-то еще (Flash Scopes, CDI разговор, @SessionScoped, ...).
    • Примите два HTTP-обхода для каждого действия пользователя.
  • Используйте какой-либо метод (например, стороннюю библиотеку или пользовательский код), чтобы скрыть имя страницы в URL, всегда используя один и тот же общий URL для каждой страницы.

Если "?faces-redirect=true" так хорошо, как есть, есть ли способ настроить целое приложение для обработки всех запросов таким образом?

2 ответа

Решение

Действительно, JSF как ориентированная на MVC инфраструктура, ориентированная на приложения, отправляет форму POST по тому же URL-адресу, что и страница с <h:form> запрашиваемая форма. Вы можете подтвердить это, посмотрев на <form action> URL сгенерированного вывода HTML. Это в терминах веб-разработки, характеризуемых как постбэк. Навигация по обратной передаче по умолчанию не вызывает нового запроса на новый URL, но вместо этого загружает целевую страницу как содержимое ответа. Это действительно сбивает с толку, когда вам просто нужна постраничная навигация.

Как правило, правильный подход к навигации / перенаправлению зависит от бизнес-требований и идемпотентности (читай: "закладка") запроса (примечание: для конкретных примеров кода см. Ссылки "См. Также" ниже).

  • Если запрос идемпотентен, просто используйте форму / ссылку GET вместо формы POST (т.е. используйте <a>, <form>, <h:link> или же <h:button> вместо <h:form> а также <h:commandXxx>).
    Например, постраничная навигация, Google-подобная форма поиска и т. Д.

  • Если запрос не идемпотентен, просто покажите результаты условно в том же представлении (т.е. верните null или же void от метода действия и использовать, например, <h:message(s)> и / или rendered).
    Например, ввод / редактирование данных на странице, многошаговый мастер, модальное диалоговое окно, форма подтверждения и т. Д.

  • Если запрос не идемпотентен, но целевая страница идемпотентна, просто отправьте перенаправление после POST (т.е. верните результат с ?faces-redirect=true из метода действия, или вызвать вручную ExternalContext#redirect()или положить <redirect/> в устаревшем случае навигации XML).
    Например, отображение списка всех данных после успешного редактирования, перенаправление после входа в систему и т. Д.

Обратите внимание, что чистая постраничная навигация, как правило, идемпотентна, и именно здесь многие начинающие JSF терпят неудачу, злоупотребляя командными ссылками / кнопками, а затем жалуются, что URL не меняются. Также обратите внимание, что навигационные примеры очень редко используются в реальных приложениях, которые разрабатываются в отношении SEO/UX, и именно здесь многие учебники по JSF терпят неудачу, позволяя читателям поверить в обратное.

Также обратите внимание, что использование POST абсолютно не "более безопасно", чем GET, потому что параметры запроса не сразу видны в URL. Они по-прежнему видны в теле HTTP-запроса и по-прежнему могут использоваться. Так что нет абсолютно никакой причины предпочитать POST для идемпотентных запросов ради "безопасности". Настоящая безопасность заключается в использовании HTTPS вместо HTTP и проверке в методах бизнес-служб, разрешено ли текущему вошедшему в систему пользователю запрашивать объект X или манипулировать объектом X и т. Д. Достойная структура безопасности предлагает для этого аннотации.

Смотрите также:

Немного поздно, но я опубликую свой обходной путь здесь. У меня был тот же вопрос, но я не нашел этот пост, пока я не разместил. В приведенном ниже коде я обновляю URL вручную через перенаправление, как упомянуто выше, но программно, а не через html. Это соответствует моим целям. Приложение перейдет на новую страницу, а URL обновится. Использование метода "return string" предотвращает обновление URL-адреса, поэтому просто замените каждый из них перенаправлением ExternalContext, и все должно быть в порядке. Спасибо за объяснение.

public void viewGroups(){

ExternalContext ec = FacesContext.getCurrentInstance()
        .getExternalContext();
try {

     ec.redirect(ec.getRequestContextPath()
                + "/viewgroups.xhtml");

} catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

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