Problem z sesją w JSF

Odpowiedz Nowy wątek
2011-07-30 14:42
kzz
0

Witam.
Na początku zaznaczę, że programowaniem w Javie zajmuję się od kilku lat, ale JEE uczę się dopiero od tygodnia.
Mój problem dotyczy zarządzaniem sesją w JSF. Napisałem prostą aplikację, która po zalogowaniu usera, ustawia odpowiedni obiekt UserSessionBean jako atrybut sesji, tak aby mieć potem wygodny do niego dostęp. Sam proces logowania odbywa się poprzez prosty formularz (używam kontrolek PrimeFaces, stąd <p:...>):

<h:form>
 
            <p:panel header="Logowanie">
                <h:panelGrid columns="2">  
                    <h:outputText value="Użytkownik: " />
                    <p:inputText value="#{userForm.userName}"/>
                    <h:outputText value="Hasło: " />
                    <p:password value="#{userForm.password}" feedback="false" minLength="3"/>
                    <p:commandButton value="Zaloguj" action="#{userForm.login}" update="growl" ajax="false"/>
                </h:panelGrid>
            </p:panel>
 
        </h:form>

Klasa odpowiedzialna za logowanie (najważniejszy fragment):

@ManagedBean(name = "userForm")
@SessionScoped
public class UserForm implements HttpSessionListener{
 
    private PostgreManager pm;
    @ManagedProperty(value = "#{userSession}")
    private UserSessionBean userSession;
    private String userName;
    private String password;
 
    public String login() {
        try {
            try {
                pm = PostgreManager.getInstance();
            } catch (ClassNotFoundException ex) {
                Logger.getLogger(UserForm.class.getName()).log(Level.SEVERE, null, ex);
            }
            UserBean user = null;
            try {
                user = pm.validateLogin(getUserName(), getPassword(), false);
            } catch (NoSuchAlgorithmException ex) {
                Logger.getLogger(UserForm.class.getName()).log(Level.SEVERE, null, ex);
            }
 
            if (user != null) {
 
                HttpSession session = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(true);
 
                userSession = (UserSessionBean) session.getAttribute(UserSessionFilter.MANAGED_BEAN_NAME);
                userSession.setUser(user);
                session.setAttribute(UserSessionFilter.MANAGED_BEAN_NAME, userSession);
 
                return "valid";
            } else {
                // Do your error handling thing.
                setErrorMessage("Podano zły login lub hasło.");
            }
        } catch (SQLException e) {
            // Do your exception handling thing.
            setErrorMessage("Błąd przy łączeniu z bazą.", e);
        }
 
        return null;
    }
 
    public String logout() {
 
        HttpSession session = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(false);
        userSession = (UserSessionBean) session.getAttribute(UserSessionFilter.MANAGED_BEAN_NAME);
        userSession.setUser(null);
        session.setAttribute(UserSessionFilter.MANAGED_BEAN_NAME, userSession);
        return "logout";
    }
}

W faces-config.xml mam następującą regułę, dotyczącą nawigacji:

<navigation-rule>
    <from-view-id>/login.xhtml</from-view-id>
    <navigation-case>
        <from-outcome>valid</from-outcome>
        <to-view-id>/view.xhtml</to-view-id>
        <redirect/>
    </navigation-case>
</navigation-rule>

Mój problem polega na tym, że podczas logowania, przy przechodzeniu z /login.xhtml do /view.xhtml sesja zostaje zamknięta (sprawdzałem to ustawiając odpowiedni HttpSessionListener ) a w jej miejsce zostaje wstawiona nowa sesja, przez co nie mam już dostępu do atrybutu UserSessionBean. Dodam, że w web.xml timeout jest standardowy = 30 minut. Co może być tego powodem i jak sprawić, aby sesja nie została usunięta.

Dodam jeszcze stack trace, jaki otrzymałem po umyślnym wyrzuceniu wyjątku w metodzie sessionDestroyed() obiektu nasłuchującego:

2011-07-30 15:18:13 UserForm sessionDestroyed
FINE: Niszczenie sesji
java.lang.Exception: sesja zlikwidowana
    at UserForm.sessionDestroyed(UserForm.java:152)
    at org.apache.catalina.session.StandardSession.expire(StandardSession.java:807)
    at org.apache.catalina.session.StandardSession.expire(StandardSession.java:769)
    at org.apache.catalina.session.StandardSession.isValid(StandardSession.java:686)
    at org.apache.catalina.session.StandardManager.processExpires(StandardManager.java:996)
    at org.apache.catalina.core.StandardContext.backgroundProcess(StandardContext.java:5717)
    at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1790)
    at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(ContainerBase.java:1779)
    at java.lang.Thread.run(Thread.java:662)

Wygląda na to, że moja sesja wygasła z nieznanych mi przyczyn.

Pozostało 580 znaków

2011-07-30 17:46
0

Moje doświadczenie w JSF jest niewielkie ale w aktualnym JSF2 faces-config.xml ma niewiele do gadania (w nowostworzonym projekcie go nawet nie ma), bo się większość załatwia poprzez dyrektywy.

Poza tym metoda którą wywołujesz przez ActionButton, czy tam ActionCommand z PrimeFaces, to przy poprawnym zalogowaniu mógłby zwrócić Stringa do której strony ma przenieść zamiast null.

Czyli zamiast return null;, to return "/view.xhtml";. A nulla zwraca przy niepowodzeniu jakimś.

Ze stacka wychodzi, że sesja wygasła:/ Swoją drogą: skoro użytkownik i tak się loguje, to mógłbyś utworzyć nową sesję, ew. starą zamknąć. Nie wiem w którym ziarnie ci wywala wyjątek z tą sesją.

Pozostało 580 znaków

2011-07-30 19:23
kzz
0

@Razi91: Ta metoda działa dokładnie tak jak napisałeś. Przy poprawnym logowaniu zwraca ciąg "valid",
co zgodnie z regułą zapisaną w faces-config.xml powoduje przekierowanie na stronę /view.xhtml.
Null jest zwracany, gdy nie znaleziono usera w bazie. W tym przypadku strona nie zostaje przeładowana,
wyświetla się za to okienko z komunikatem o niepoprawnym loginie.

Robiłem testy w których w identyczny sposób realizowałem logowanie, ale bez użycia primefaces.
W takim przypadku sesja była inicjowana na początku działania i trwała, dopóki nie upłynął zadany czas.
Wygląda na to, że primefaces w jakiś sposób wpływa na wcześniejsze zamknięcie sesji.

Pozostało 580 znaków

2011-07-30 20:19
kzz
0

Okazuje się, że jestem kretynem w dodatku zapominalskim. W czasie jednego z poprzednich eksperymentów zostawiłem w kodzie jednego z rzadko używanych ziaren funkcję zmieniającą czas życia sesji na 5 ms i zapomniałem jej po wszystkim stamtąd usunąć, co kosztowało mnie 8 godzin szukania o_O
Problem rozwiązany.

uroki programowania :d - remigio 2011-07-30 20:28

Pozostało 580 znaków

2012-03-05 22:41
0

Super, że znalazłeś przyczynę błędu, ja mam taki sam kawałek kodu i problem z tym, że nie pobiera mi wartości z danego pola tekstowego w formularzu natomiast do gettera mi wchodzi i w debugerze widzę że jest wartość null ponieważ settera mi nie wywołuje. Natomiast ten kawałek kodu nad prywatną zmienną, która ustawia setter @ManagedProperty(value="#{firstname}") nie przekazuje wartości z pola formularza o tej właśnie nazwie. Czy ktoś wie jak to rozwiązać? Będę wdzięczny.

Odpowiedz
Liczba odpowiedzi na stronę

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0