Модераторы: LSD, AntonSaburov
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> JSF жизненный цикл, Не могу разобраться 
V
    Опции темы
Ovsyanka
Дата 30.10.2008, 13:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 9
Регистрация: 29.10.2008

Репутация: нет
Всего: нет



Здравствуйте. Я совсем недавно начал работать с JSF и зачастую программа работает не так, как я планировал, а почему она работает именно так я понять не могу) 
Я сначала коротко опишу задачу и что я сделал:
Мне нужно сделать чат с использованием модального окна.
Есть некоторая страничка. Я добавил ссылку, которая показывает модальное окно. В нем есть таблица, в которой будут показываться входящие сообщения, поле для написания текста сообщения, поле для ввода имени(для кого сообщение), кнопка закрытия и кнопка отправки сообщения. 
Я хочу написать так, чтобы процесс происходил в следующем порядке:
1. Загружается вся форма, включая модальное окно(оно просто не отображается).
2. При нажатии на ссылку, ничего никуда не отправляется, просто показывается модальное окно.
3. При нажатии на кнопку отправить, должен считаться текст(и обнулиться) и имя, затем вызваться chat.sendMessage(ф-я отправки сообщения). А потом обновиться уже таблица с новыми сообщениями. 

Вот с третим пунктом у меня проблемы: все время получается, что у меня вызывается ф-я getNewMessages до sendMessages...
Я пробовал добавить аттрибуты immediate, ajaxSingle, bypassUpdates, но все равно getNewMessages вызывается...
У меня есть книга по Java Server Faces и я пытался найти ответ в ней, но, видимо пока я не в силах понять правильно то, что там написано ))

Вот исходные коды:
    .xhtml
Код

............

<a4j:commandLink type="button" id="openChat" title="Open chat" value="Новых сообщений: #{chat.newMessagesCount}">
    <rich:componentControl for="panelChat" attachTo="openChat" operation="show" event="onclick" />
</a4j:commandLink>

............

<ui:define name="innerForm">
    <rich:modalPanel id="panelChat" width="750" height="500">
        <f:facet name="header">
            <h:panelGroup>
                <h:outputText value="Chat Panel"></h:outputText>
            </h:panelGroup>
        </f:facet>
        <f:facet name="controls">
            <h:panelGroup>
                <a4j:commandButton value="close" reRender="openChat" id="bhidelink" title="close chat" />
                    <rich:componentControl for="panelChat" attachTo="bhidelink" operation="hide" event="onclick" />
            </h:panelGroup>
        </f:facet>
        <h:form id="chatForm">
            <h:dataTable id="listOfMessages" value="#{chat.newMessages}" var="row">
                <h:column>
                    <h:outputText id="test" value="#{row.sender}: " style="font-weight: bold" />
                    <h:outputText value="#{row.text}" />
                </h:column>
            </h:dataTable>
                        
            <h:inputTextarea id="inputMessage" value="#{chat.outgoingMessage}"></h:inputTextarea>
            <h:inputText id="inputTargetName" value="#{chat.targetName}" required="true"></h:inputText>
            <a4j:commandButton immediate="true"  title="send message" id="bSend" value="send" type="button"  
                            action="#{chat.sendMessage}" style="position: absolute; right: 50px; bottom: 0px" />
        </h:form>
    </rich:modalPanel>
</ui:define>

..................


    Chat.java
Код

..................

@Name("chat")
@Scope(ScopeType.SESSION)
public class Chat extends ASeamBaseBean {
    private int newMessagesCount;
    private ChatMessages c;
    private String outgoingMessage;
    private String targetName;
    private String login = this.getCurrentUser().getLogin();
    private static final Log logger = LogFactory.getLog(DictionaryCache.class);
    
    public String getTargetName() {return targetName;}

    public void setTargetName(String targetName) {this.targetName = targetName;}

    @In(value = "ChatMessages")
    public void setC(ChatMessages chatMessages) {
        c = chatMessages;
    }

    public int getNewMessagesCount() {
        newMessagesCount = c.getNewMessagesCount(login);
        return newMessagesCount;
    }

    public List<TMessage> getNewMessages() {
        logger.debug("getNewMessages");
        List<TMessage> result = new ArrayList<TMessage>();
        for(TMessage msg:c.getMessages(login)){
            if(msg.getStatus()==0) {
                result.add(msg);
                msg.setStatus(1);
            }
        }
        this.newMessages = result;
        return result;
    }

    public void setOutgoingMessage(String outgoingMessage) {this.outgoingMessage = outgoingMessage;}

    public String getOutgoingMessage() {
        logger.debug("getOutgoingMessage");
        return outgoingMessage; 
    }
    
    public String sendMessage(){
        logger.debug("sendMessage");
        c.sendMessage(login, targetName, outgoingMessage);
        this.outgoingMessage="";
        return "send";
    }
}


    ChatMessages.java
Код

....................

@Name("ChatMessages")
@Scope(ScopeType.APPLICATION)
@Startup
public class ChatMessages extends ASeamBaseBean {
    
    private List<TMessage> messages= new ArrayList<TMessage>();

    public int getNewMessagesCount(String name){
        int result = 0;
        for(TMessage m:messages){
            if (m.getStatus()==0) result++;
        }
        return result;
    }

    public List<TMessage> getNewMessages(String name){
        List<TMessage> result = new ArrayList<TMessage>();
        for(TMessage m:messages){
            if (m.getTarget().equals(name)) result.add(m);
        }
        return result;
    }
    
    public void sendMessage(String fromName, String forName,String msg){
        TMessage m = new TMessage(fromName,forName,msg);
        messages.add(m);
    }
}


     TMessage.java
Код

..............

public class TMessage {
    private String sender;
    private String target;
    private String text;
    private int status = 0; //прочитано или нет 0-не прочитано
    
    public TMessage(String fromName, String forName, String text){
        this.sender = fromName;
        this.target = forName;
        this.text = text;
    }
    
    public String getSender() {return sender;}
    public void setSender(String sender) {this.sender = sender;}
    public String getTarget() {return target;}
    public void setTarget(String target) {this.target = target;}
    public String getText() {return text;}
    public void setText(String text) {this.text = text;}
    public int getStatus() {return this.status;}
    public void setStatus(int status) {this.status = status;}
}


Буду благодарен, если кто-то объяснит почему так может происходить или подскажет как иначе мне это реализовать.
Извините, если я что-то сказать забыл, я практически не писал на форумах раньше.
Спасибо)

Это сообщение отредактировал(а) Ovsyanka - 30.10.2008, 14:36
PM MAIL   Вверх
necromancer
Дата 30.10.2008, 14:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 317
Регистрация: 26.7.2006
Где: Москва

Репутация: 6
Всего: 7



это знакомая до боли проблема обновления дерева копнонент.
Могу посоветовать так:
у тебя выставление листа в таблице идет через value="#{getsomelist}" а попробуй в методе doMessage находить таблицу по ID и напрямую писать туда свой лист.
Недостатки - ты не сможешь выбрать через JSF запись в таблице напрямую (не используя извр методы).

либо же забей на что метод getNew... вызывается 2 раза - первый во время востановления view, второй во время рендеринга.
Просто в нем не делай никакой работы по обновлению листа, а всю работу переложи на метод doMessages, например:
Код

 private List list;
 public List getNewMessages() {
      return list;
 }
 public List doMessages() {
        ... запись сообщения
        list = ... получение списка сообщений
 }




--------------------
С уважением, 
                 Виталий Смык
----------------------------------------------------------------------------------------------
SCJP, SCWCD, OCA
http://dev.maryno.net/video/
PM MAIL WWW ICQ Skype   Вверх
Ovsyanka
Дата 30.10.2008, 15:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 9
Регистрация: 29.10.2008

Репутация: нет
Всего: нет



Второй способ у меня вопросов не вызывает, а в первом, я так понимаю находить надо с помощью FacesContext.getCurrentInstance().дальше_не_помню, а потом с помощью UIComponent создавать таблицу?

Спасибо за варианты решения, но я хотел бы еще узнать почему происходит именно так... Или это ошибка и так не должно быть?

А sendMessage вы переименовали в doMessage потому, чтчо считаете, что это более подходящее название этой ф-и?) 
PM MAIL   Вверх
necromancer
Дата 30.10.2008, 16:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 317
Регистрация: 26.7.2006
Где: Москва

Репутация: 6
Всего: 7



>А sendMessage вы переименовали в doMessage потому, чтчо считаете, что это более подходящее название этой ф-и?)  
не знаю почему ... так... подумалось. =)

вот ссылка 
http://www.ibm.com/developerworks/library/j-jsf2/

если своими словами:
после нажатия кнопки субмит, JSF востанавливает дерево компонент , т.е. у каждого компонента вызывает метод setValue() и выставляет туда значение получившееся после выполнения тела атрибута. Это первый вызов метода. Далее происходит вызов бизнес метода. И уже на последнем этапе JSF дергает тело атирбута для получения новых данных в моделе (второй вызов метода)

FacesContext.getCurrentInstance().getView().findComponent("<formid>:<componentid>").get|setValue
учти при вызове getValue у найденого компонента будет выполнено тело атрибута у соотв. тэга.

>потом с помощью UIComponent создавать таблицу
нет необходимости, таблица уже пристуствует на view нужно просто получить к ней доступ и записать туда свой лист.

так же можно инициализировать значения в момент получения компонента (см. биндинг компонент), но данный метод имеет кучу недостатков ИМХО, в том числе завязывает логику с представлением и реализацией JSF.


--------------------
С уважением, 
                 Виталий Смык
----------------------------------------------------------------------------------------------
SCJP, SCWCD, OCA
http://dev.maryno.net/video/
PM MAIL WWW ICQ Skype   Вверх
Ovsyanka
Дата 1.11.2008, 12:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 9
Регистрация: 29.10.2008

Репутация: нет
Всего: нет



Спасибо) только вот у меня же указан аттрибут type="button", читая книгу, я так понял, что в таком случае форма отправляться не должна... 
PM MAIL   Вверх
necromancer
Дата 1.11.2008, 13:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 317
Регистрация: 26.7.2006
Где: Москва

Репутация: 6
Всего: 7



этот аттрибут type ты где собрался указывать? в тэге input? =) в JSF компонентах нет такого тэга =) есть только:
h:commandButton
h:commandLink

форма может быть отправлена и по событию из JS


--------------------
С уважением, 
                 Виталий Смык
----------------------------------------------------------------------------------------------
SCJP, SCWCD, OCA
http://dev.maryno.net/video/
PM MAIL WWW ICQ Skype   Вверх
Ovsyanka
Дата 5.11.2008, 10:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 9
Регистрация: 29.10.2008

Репутация: нет
Всего: нет



Ну так он у меня указан в a4j:CommandButton (см. .xhtml 32,33 строки)
PM MAIL   Вверх
necromancer
Дата 5.11.2008, 10:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 317
Регистрация: 26.7.2006
Где: Москва

Репутация: 6
Всего: 7



ты наверное попутал =) с вот этим:
immediate="true" 
но сути проблемы это не отменяет. дерево компонент все равно будет инициализироватся а потмо еще рендерится, т.е. вызов будет 2 раза (ИМХО)


--------------------
С уважением, 
                 Виталий Смык
----------------------------------------------------------------------------------------------
SCJP, SCWCD, OCA
http://dev.maryno.net/video/
PM MAIL WWW ICQ Skype   Вверх
Ovsyanka
Дата 5.11.2008, 11:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 9
Регистрация: 29.10.2008

Репутация: нет
Всего: нет



Ну как так перепутал? )) 
Код

            <a4j:commandButton immediate="true"  title="send message" id="bSend" value="send" type="button"  
                            action="#{chat.sendMessage}" style="position: absolute; right: 50px; bottom: 0px" />

Вот у меня здесь type="button" указан...
PM MAIL   Вверх
necromancer
Дата 5.11.2008, 12:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 317
Регистрация: 26.7.2006
Где: Москва

Репутация: 6
Всего: 7



immediate    
True means, that the default ActionListener should be executed immediately (i.e. during Apply Request Values phase of the request processing lifecycle), rather than waiting until the Invoke Application phase

type    
This attribute specifies a type of control to create. The possible values are "submit", "reset", "image" and "button". The default value for this attribute is "submit"

http://www.jboss.org/file-access/default/m...l#commandButton

нигде в документации не сказано что type влияет на отправку запроса. Он влияет лишь на тип элемента. Так как submit - заставляет браузер посылать запрос. А button нет, но это не относится к commandButton, он посылает запрос при помощи JS.
Зачем нужен тип(type)? ну например для CSS или для каких то действий через JS.

например тэг <a4j:commandButton image=""/> переключит в type="image" но ведь из за этого оно не перестанет посылать запросы на сервер =)

Это сообщение отредактировал(а) necromancer - 5.11.2008, 12:52


--------------------
С уважением, 
                 Виталий Смык
----------------------------------------------------------------------------------------------
SCJP, SCWCD, OCA
http://dev.maryno.net/video/
PM MAIL WWW ICQ Skype   Вверх
Ovsyanka
Дата 5.11.2008, 13:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 9
Регистрация: 29.10.2008

Репутация: нет
Всего: нет



Ага, я понял так: 
Не важно какого типа кнопка, она всегда посылает запрос на сервер. то есть получается, что нельзя сделать кнопку, которая не посылала бы запрос... 
Тогда в моем случае, кроме тех вариантов, что ты предложил можно использовать ссылку(CommandLink можно?)

А про type="button" я в книжке прочитал... видимо, не так понял.

Это сообщение отредактировал(а) Ovsyanka - 5.11.2008, 14:25
PM MAIL   Вверх
necromancer
Дата 5.11.2008, 14:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 317
Регистрация: 26.7.2006
Где: Москва

Репутация: 6
Всего: 7



можно:
1. не использовать commandButton
2. использовать commandButton без указания action и eventListener (не уверен что это возможно)
3. Использовать на форме простые html тэги
4. Использовать <h:graphicImage onClick=...
5. написать PhaseListener который бы сбрасывал запрос
6. написать Filter
7. не использовать JSF совсем =)
ну и 8 пункт ты сам придумаешь ;-)

если вопрос разрешен, ставь галочку а мне поднимай репутацию =) ЙОХА!



--------------------
С уважением, 
                 Виталий Смык
----------------------------------------------------------------------------------------------
SCJP, SCWCD, OCA
http://dev.maryno.net/video/
PM MAIL WWW ICQ Skype   Вверх
Ovsyanka
Дата 5.11.2008, 14:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 9
Регистрация: 29.10.2008

Репутация: нет
Всего: нет



Да, похоже, что решен.

Основное, что я хотел узнать, это почему у меня отправляется форма. Я узнал - потому, что commandButton всегда ее отправляет вне зависимости от type. 
Кроме этого тут написалось еще несколько полезных мыслей)

Спасибо за помощь, тему закрываю.
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   tux
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java EE (J2EE) и Spring | Следующая тема »


 




[ Время генерации скрипта: 0.0527 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.