Боб с областью действия сеанса доступа из боба с областью действия запроса


Я пытаюсь использовать шаблон, найденный на странице IceFaces.(Я не использую IceFaces, используя PrimeFaces)

В этом случае у меня есть два боба:

UserController и Usermodel

На моей UserModel у меня есть экземпляр UserVO (созданный другим программистом). На моем UserController у меня есть это:

@ManagedBean
@RequestScoped
public class UserController implements Serializable
{

    private static final long serialVersionUID = 1L;
    private UserBO bo;
    private UserModel model;

    public UserController()
    {
        bo = new UserBO();
        model = new UserModel();
    }

    public void Login() throws IOException
    {
        model.setUserVo(bo.executeLogin(model.getUserVo()));
        ExternalContext externalContent = FacesContext.getCurrentInstance().getExternalContext();
        if (!model.getUserVo().isError())
        {
            model.setLoggedIn(true);
            externalContent.getSessionMap().put("userSession", model);
            externalContent.redirect(externalContent.getRequestContextPath() + "/views/request/search.html");
        } else
        {
            model.setLoggedIn(false);
            FacesMessage facesMessage = new FacesMessage(FacesMessage.SEVERITY_ERROR, model.getUserVo().getMessage(), model.getUserVo().getLogin());
            FacesContext.getCurrentInstance().addMessage(null, facesMessage);
        }
    }

    public UserBO getBo()
    {
        return bo;
    }

    public void setBo(UserBO bo)
    {
        this.bo = bo;
    }

    public UserModel getModel()
    {
        return model;
    }

    public void setModel(UserModel model)
    {
        this.model = model;
    }
}

Как вы можете видеть, я создаю новый экземпляр UserModel и устанавливаю его с тем, что было возвращено из bo.executeLogin() и это работает, мой объект возвращается.

Чтобы убедиться, что пользователь вошел в систему, у меня есть свойство на моей UserModel :

@ManagedBean
@SessionScoped
public class UserModel
{

    private UserVO userVo;
    private Boolean loggedIn = false;

    public UserModel()
    {
        userVo = new UserVO();
    }

    public UserVO getUserVo()
    {
        return userVo;
    }

    public void setUserVo(UserVO userVo)
    {
        this.userVo = userVo;
    }

    public Boolean getLoggedIn()
    {
        return loggedIn;
    }

    public void setLoggedIn(Boolean loggedIn)
    {
        this.loggedIn = loggedIn;
    }

У меня есть шаблон .xhtml С:

<ui:fragment rendered="#{userModel.loggedIn}">
            <ui:include src="../includes/top.xhtml"/>
</ui:fragment>

И дело в том, что он не работает, не получает значения свойства loggedIn.

Я предполагаю, что доступ таким образом я как бы создаю новый экземпляр UserModel , Если это так, то это проблема, потому что мой UserController не является областью действия сеанса, только модель пользователя

EDIT

Вместо использования этого свойства loggedIn я знаю, что могу просто проверить, если UserModel userVo свойство задано, но проблема заключается в области сеанса Боба, я не могу получить доступ к нему из UserController , где он установлен, потому что это не область сеанса, и мой шаблон.xhtml будет использоваться каждой страницей.

3 4

3 ответа:

Вместо того, чтобы создавать новый экземпляр UserModel в вашем UserController, введите его с @ManagedProperty.

В UserController:

@ManagedProperty(value="#{userModel}")
private UserModel model;

// add getter and setter for userModel (important!)

Тогда вам не нужно создавать его экземпляр в конструкторе, и вы всегда получите экземпляр UserModel с областью действия сеанса в вашем контроллере.

Обновление:

Я думаю, что вы усложняете процесс входа в систему своим строгим подходом MVC. В JSF границы между моделью, видом и контроллером несколько размыты или перекрываются.

Рекомендую прочтите Этот интересный вопрос и ответы и особенно этот ответ для получения дополнительной информации по этой теме.

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

Также я бы рекомендовал объединить ваши бобы вместе в один боб. Тогда у вас нет проблем с круговым движением зависимости и нулевые ссылки.

(это было первоначально опубликовано на https://stackoverflow.com/questions/10691324/working-with-3-java-beans-controller-backing-model, но ОП удалил вопрос и я не хотел выбрасывать ответ, думаю репост на этот вопрос тоже подойдет)

Вы, вероятно, слишком много внимания уделяли этому блогуICEfaces , который содержитВ основном чепуху .

У вас должен быть один управляемый Боб JSF, который действует как контроллер, у вас уже есть: UserController. У вас должен быть простой объект bean, который представляет модель, у вас уже есть: UserVO. У вас должен быть корпоративный боб, который представляет службу, он уже есть: UserBO. Эти последние два не должны быть управляемыми бобами JSF.

Основываясь на истории ваших вопросов, вы используете Glassfish, таким образом, вы можете использовать JPA и EJB. Таким образом, класс модели должен быть JPA @Entity, А класс обслуживания-EJB @Stateless.

Использование случай с "пользователем входа", однако, особенный. Вы не хотите, чтобы сущность была управляемым Бобом с областью действия сеанса, иначе она будет неявно создана JSF. Вам лучше самому внести его в область сеанса, чтобы вы могли проверить #{not empty user}, вошел ли пользователь в систему или нет.

Все вместе это должно выглядеть примерно так:

@Entity
public class User {

    private String username;
    private String password;

    // ...
}
@Stateless
public class UserService {

    @PersistenceContext
    private EntityManager em;

    public User find(String username, String password) {
        return em.createQuery("SELECT u FROM User u WHERE username = :username AND password = MD5(:password)", User.class)
           .setParameter("username", username)
           .setParameter("password", password)
           .getSingleResult();
    }

}
@ManagedBean
@ViewScoped
public class UserController {

    private String username;
    private String password;

    @EJB
    private UserService service;

    public String login() {
        FacesContext context = FacesContext.getCurrentInstance();

        try {
            User user = userService.find(username, password);
            context.getExternalContext().getSessionMap().put("user", user);
            return "/views/commons/home.html?faces-redirect=true";
        }
        catch (NoResultException) {
            context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Unknown login, please try again", null));
            return null;
        }
    }

    public String logout() {
        FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
        return "/views/commons/login.html?faces-redirect=true";
    }

    // ...
}

С

<h:form>
    <h:inputText value="#{userController.username}" required="true" />
    <h:inputSecret value="#{userController.password}" required="true" />
    <h:commandButton value="login" action="#{userController.login}"/>
    <h:messages />
</h:form>

Альтернативно, вы можете сделать UserController сеансовым Бобом, который содержит сущность User, Вы бы нужно только добавить дополнительный метод, чтобы проверить, вошел ли пользователь в систему или нет, чтобы вы могли использовать его в EL by #{userController.loggedIn}.

@ManagedBean
@SessionScoped
public class UserController {

    private User user = new User();

    @EJB
    private UserService service;

    public String login() {
        FacesContext context = FacesContext.getCurrentInstance();

        try {
            user = userService.find(user.getUsername(), user.getPassword());
            return "/views/commons/home.html?faces-redirect=true";
        }
        catch (NoResultException) {
            context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Unknown login, please try again", null));
            return null;
        }
    }

    public String logout() {
        FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
        return "/views/commons/login.html?faces-redirect=true";
    }

    public boolean isLoggedIn() {
        return user.getId() != null;
    }

    // ...
}

С

<h:form>
    <h:inputText value="#{userController.user.username}" required="true" />
    <h:inputSecret value="#{userController.user.password}" required="true" />
    <h:commandButton value="login" action="#{userController.login}"/>
    <h:messages />
</h:form>

Вы можете использовать инъекцию зависимостей, чтобы получить значения из этого Бина с областью действия сеанса.

@Inject UserModel user; 

Тогда вы можете использовать этот объект в вашем Бине UserControl. Кстати, вам не нужно реализовывать serializable, когда вы имеете дело с бобами RequestScope.