Access session scoped bean from request scoped bean

别说谁变了你拦得住时间么 提交于 2019-11-28 08:49:51
Matt Handy

Instead of creating a new UserModel instance in your UserController, inject it with @ManagedProperty.

In UserController:

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

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

Then you don't have to instantiate it in the constructor and will always get the session scoped instance of UserModel in your controller.

UPDATE:

I think you are complicating the login process with your strict MVC approach. In JSF the borderlines between model, view and controller are somewhat blurred or overlapping.

I recommend reading this interesting question and answers and especially this answer for more information on that topic.

As to your concrete problem. I am not quite sure what is the reason but what you should definitely avoid is to instantiate managed bean by youself and fiddle around with both injected and self-initialized instances of beans.

Also I would recommend to merge your beans together into a single bean. Then you don't have the problems with circular dependencies and null references.

BalusC

(this was originally posted on https://stackoverflow.com/questions/10691324/working-with-3-java-beans-controller-backing-model, but the OP deleted the question and I didn't want to throw away the answer, I think a repost on this question is suitable as well)

You were probably focusing too much on this ICEfaces blog which contains mainly nonsense.

You should have a single JSF managed bean which acts as a controller, you already have it: UserController. You should have a simple entity bean which represents the model, you already have it: UserVO. You should have an enterprise bean which represents the service, you already have it: UserBO. Those last two doesn't need to be JSF managed beans.

Based on your question history you're using Glassfish, thus you can make use of JPA and EJB. So the model class should be a JPA @Entity and the service class should be a @Stateless EJB.

The use case of a "login user" is however special. You don't want to have the entity as a session scoped managed bean, or it would be implicitly created by JSF. You'd better put it straight in the session scope yourself, so that you can check on #{not empty user} if the user is logged in or not.

All with all it should look something like this:

@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";
    }

    // ...
}

with

<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>

Alternatively, you can make the UserController a session scoped bean which holds the User entity, you'd only need to add an extra method to check if the user is logged in or not so that you can use it in 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;
    }

    // ...
}

with

<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>

You might use dependency injection to get the values from that bean with session scope.

@Inject UserModel user; 

Then you might use this Object in your UserControl bean. By the way you don't need to implement serializable when you are dealing with RequestScope beans.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!