Обновление вида бобов JSF, введенных в область видимости
@SessionScoped public class User {
... //settings, attributes, etc
}
@ViewScoped public class FooController {
@ManagedProperty(value="#{user}")
private User user;
...
}
@RequestScoped public class LoginController {
@ManagedProperty(value="#{user}")
private User user;
public String login() {
//handle Servlet 3.0 based authenticate()... if success, make new User object and slap it into context
request.getSession().setAttribute("user", user);
return "?faces-redirect=true";
}
...
}
Страницы xhtml включают элементы управления входом практически на каждой странице. Идеальным было бы, чтобы они могли войти, и страница обновится, а существующие FooController
будет иметь ссылку на текущего вошедшего в систему пользователя, который условно отображает кнопки / элементы. Поведение состоит в том, что вход в систему происходит, но FooController
view по-прежнему "действителен", поэтому управляемый бин никогда не будет пытаться внедриться снова. Если я перейду со страницы и вернусь на нее [восстанавливаю bean-объект области видимости], пользовательский bean-компонент будет добавлен заново... но я бы предпочел, чтобы этот промежуточный шаг не выполнялся. Есть идеи?
Я пробовал различные формы FacesContext.getCurrentInstance().getViewRoot().getViewMap().remove("user");
в надежде, что он вытащит его из сессии, но безрезультатно. Я не хочу тесно связывать код в моем LoginController, чтобы ссылаться на недействительную FooController, BarController или любую другую, ссылающуюся на пользовательский компонент.
2 ответа
Хорошо, я понял это по дороге домой, это была проблема жизненного цикла. Я пытался заставить JSF сделать что-то, чего не следует делать с управляемыми бинами.
Вместо нового User
объект и переназначить его на управляемый экземпляр user
в LoginController
, я изменил метод входа в систему, чтобы выглядеть так:
public String login() {
//handle Servlet 3.0 based authenticate()... if success...
User loadedFromDB = someDao.load(principal.getName());
user.setDefaultPage(loadedFromDB.getDefaultPage()); // NOTE: The user object IS THE MANAGED BEAN
user.setDefaultScheme(loadedFromDB.getDefaultScheme()); // This is the same object the view scoped bean has a ref on, so directly setting that object's fields proliferates that to any other bean that has the user in scope.
... //etc... not calling NEW, not reassigning object ref to user
loadedFromDB = null;
return "?faces-redirect=true";
}
Это завершает то, что было необходимо. Кто бы знал, если вы прекратите бороться с фреймворком на минуту и просто используете его, это поможет вам:)
Почему вы пытаетесь удалить user
(а @SessionBean
), от viewMap
(карта @ViewScoped
объекты в текущем сеансе)?
Вы должны удалить FooController
, @ViewScoped
фасоль из viewMap
т.е.
FacesContext.getCurrentInstance().getViewRoot().getViewMap().remove("fooController");.
Это то, что избавит от видоизмененного боба и заставит создать новый. Тогда, конечно, вам все равно придется обновить страницу.
Если вы намереваетесь удалить сессионный компонент, вы должны получить прямой доступ к сеансу:
FacesContext.getCurrentInstance().getExternalContext().getSessionMap().remove("user");.
Это избавляет от объекта пользователя