| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > Java EE (J2EE) и Spring > JSF/HtmlCommandLink - программно установить action |
| Автор: Dims 3.6.2008, 20:47 | ||||
| У меня в задаче есть "категории", к каждой категории принадлежат "статьи". У меня есть главная страница, на которой я вывожу список категорий. Каждая категория представляет собой ссылку. Все ссылки должны вести на вторую страницу, на которой должен выводиться список статей выбранной категории. Для обеспечения этого, на главной странице я программно формирую HtmlPanelGrid и заполняю его объектами HtmlCommandLink. Каждый HtmlCommandLink, по моему представлению, должен сделать две вещи: 1) запомнить выбранную категорию в бине 2) вернуть системе JSF строку, которая указывает перемещение между страницами. Вот так у меня описано правило перехода:
Вот так я пытаюсь оформить код:
Страница с категориями показывается нормально, но при нажатии ссылки возникает исключение, которое я не понимаю. SiteController -- это бин, который следит за перемещениями по сайту. type Exception report message description The server encountered an internal error () that prevented it from fulfilling this request. exception javax.servlet.ServletException: com.telesmi.SiteController$1 javax.faces.webapp.FacesServlet.service(FacesServlet.java:256) org.netbeans.modules.web.monitor.server.MonitorFilter.doFilter(MonitorFilter.java:390) root cause java.lang.IllegalStateException: com.telesmi.SiteController$1 javax.faces.component.StateHolderSaver.restore(StateHolderSaver.java:98) javax.faces.component.UIComponentBase.restoreAttachedState(UIComponentBase.java:1406) javax.faces.component.UIComponentBase.restoreState(UIComponentBase.java:1272) javax.faces.component.UICommand.restoreState(UICommand.java:332) javax.faces.component.html.HtmlCommandLink.restoreState(HtmlCommandLink.java:876) javax.faces.component.UIComponentBase.processRestoreState(UIComponentBase.java:1141) javax.faces.component.UIComponentBase.processRestoreState(UIComponentBase.java:1157) javax.faces.component.UIComponentBase.processRestoreState(UIComponentBase.java:1157) javax.faces.component.UIComponentBase.processRestoreState(UIComponentBase.java:1157) com.sun.faces.application.StateManagerImpl.restoreState(StateManagerImpl.java:581) com.sun.faces.application.StateManagerImpl.restoreView(StateManagerImpl.java:89) com.sun.faces.application.ViewHandlerImpl.restoreView(ViewHandlerImpl.java:290) com.sun.faces.lifecycle.RestoreViewPhase.execute(RestoreViewPhase.java:141) com.sun.faces.lifecycle.LifecycleImpl.phase(LifecycleImpl.java:251) com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:117) javax.faces.webapp.FacesServlet.service(FacesServlet.java:244) org.netbeans.modules.web.monitor.server.MonitorFilter.doFilter(MonitorFilter.java:390) |
| Автор: v2v 3.6.2008, 23:02 |
| покажи код jsp страницы, где это происходит. |
| Автор: Dims 3.6.2008, 23:19 | ||
Вот код:
|
| Автор: v2v 4.6.2008, 12:44 | ||
замени на
а в функции возвращай строку "select". |
| Автор: Dims 4.6.2008, 23:43 |
| Так не получится. У меня каждая ссылка -- это категория. Она должна как-то передавать выбранную категорию на следующую страницу. Для этого надо как-то запомнить в бине эту категорию, а команда action="#{controller.select}" этого не обеспечивает. Поэтому я динамически, в программе, присобачиваю к каждой ссылке свой обработчик. Но вот как правильно сделать action -- не пойму. Пример, который ты исправил -- закомментирован и не используется. Это я пробовал, работают ли вообще переходы. |
| Автор: ivg 5.6.2008, 12:58 | ||||||||||
JSF по окончании обработки запроса сохраняет состояние View, а в начале обработки следующего восстанавливает его. Под View в данном случае понимается дерево JSF компонентов расположенных на странице. Для обеспечения этой функциональности каждый компонент реализует интерфейс javax.faces.component.StateHolder, а точнее реализован он в базовом классе, а в классах компонентов переопределяются его методы saveState() и restoreState(). Код этих методов определяет набор полей достаточных для сохранения и восстановления состояния компонента. В этот набор входит список слушателей (Listeners), а вызов HtmlCommandLink.addActionListener() пополняет этот список. Для успешного сохранения и восстановления состояния компонента каждый такой Listener должен "имплементировать" либо StateHolder интерфейс, либо Serializable (подробнее: спецификация JSF, "State Management"). Для превращения объектов, хранящих информацию о состоянии компонента, в последовательность байт используется сериализация. Для анонимного класса определённого внутри метода сериализация "весьма не рекомендуется", если вообще возможна, ибо потянет за собой не только объект бина SiteController, но и потребует сериализовать фрэйм локальных переменных метода. Вариантов решения ситуации много. Во первых предлагаю избавиться от динамического формирования списка категорий в коде. Для этого можно использовать итерационный тег на странице, например <c:forEach var="cat" items="#{controller.categs}" ... >. А во вторых, что касается передачи значения выбранной категории, то например использовать обычные ссылки в виде:
либо
а в методе getCategory() получаете ID категории:
Если формирование списка категорий в коде - условие неизменное то код аналогичный
выглядит так
Ну и в конце концов можно сделать как вы хотели, только создать отдельный класс, который implements ActionListener, Serializable, в конструктор его передавать категорию, а лучше ID, в методе processAction() достаете из сессии объект бина SiteController и устанавливаете у него выбранную категорию. Следует заметить, что явно прописывать в коде имя бина, которое является настраиваемым параметром, - не есть хорошо. |