JSF 我在从托管更改为 CDI 时丢失会话状态



编辑:这是一个史诗般的手掌局面。SessionScoped的导入错误。昨晚检查时太累了,我确信我使用的是企业会话coped导入,而我仍然使用faces会话coped导出。我把这个留给像我这样的傻瓜


现在是这个项目的早期阶段。在使用托管bean实现了这一点之后,我将托管bean更改为CDI-beans,因为这似乎是关于最佳做事方式的最新共识,但这破坏了以前的工作代码

Happy Path(摘要…详细代码摘录如下)

如果用户未登录,请显示登录或注册链接
如果用户登录,则显示用户首选项或注销链接

现在有CDI的Crappy Path(我不怪CDI)

如果用户未登录,请显示登录或注册链接
如果用户登录,仍然可以看到登录或注册链接。(坏的,坏的应用程序)

涉及的对象是

  1. 一个facelet菜单面板(带有一个primefaces登录对话框……我不认为这与它有任何关系,但为了完整起见,它包括在内),无论是否登录,都具有渲染属性
  2. 会话范围的用户bean
  3. 用于将用户登录和注销的请求范围的身份验证bean

下面列出了使用的对象。实现为CDI-beans。

小面

<h:panelGroup id="loginPanel" rendered="#{!user.loggedIn}">
    Show login buttons and stuff
</h:panelGroup>
 <h:panelGroup id="logoutPanel" rendered="#{user.loggedIn}">
    Show logout buttons and stuff
</h:panelGroup

身份验证bean

@Named(value = "webAuthenticationBean") //formerly managedbean
@RequestScoped
public class WebAuthenticationBean implements Serializable {
    @Inject private UserBean user; //formerly a managed property which worked
...
request.login(uername, password);
user.setuserdata(username); // sessionscoped user state here used to check login state among other things later.
...
return(true) // they are now logged in

用户bean

@Named(value = "user") //formerly managedbean
@SessionScoped
public class UserBean implements Serializable {
    @EJB
    private UserService userService; //stateless session bean
    private userInfo = new UserInfo(); // keeps user state and can be used as a DTO/VO
@PostConstruct
    public void init() {
    //sets default state to "guest user". This is NOT a logged in state
    }
public void setuserdata(String username){
     userInfo = userService.getUserInfo(username);
    // method called from WebAuthenticationBean 
    // sets the user state to a non-guest user (they're logged in).
    // I can see in debug mode that this is being called and retrieving
   //  the user data from the database and setting "userInfo"
}
public void isLoggedIn() throws InvalidUserException{
    // checks state to see if they are logged in, basically a bit more than are they still a guest or not
   returns (true) if logged in 
    returns (false) if not logged in
    // this worked with managed beans
}
...

因此,以下是我在调试模式下观看时的实际用例:

Happy Path(更改为CDI bean之前)

1) 用户导航到欢迎页面
2) 查询用户bean以查看他们是否已登录(facelet中的user.loggerIn)
3) userbean检查登录状态。如果他们仍然是客人,则不会登录。
4) 它们被标识为来宾,因此isLoggedIn()返回false
5) 此时会显示"登录"按钮
6) 用户请求登录
7) 身份验证bean开始登录过程:request.login成功返回
8) authenticationbean设置用户数据:user.setuserdata(username)成功返回
9) authenticationbean loginMethod返回(它们是服务器上记录的userprincipal)

备用(糟糕)路径在此分支(愉快路径继续)

10) 菜单重新检查登录状态(user.loggedIn)
11) userbean检查适当的状态,并发现它们是有效的非来宾用户
12) userbean返回(true)他们已登录
13) 菜单显示注销按钮

Crappy Path(在我将这些更改为CDI bean后会发生什么)

10) 菜单重新检查登录状态(user.loggedIn)
11) userbean检查适当的状态,发现他们是访客//更新后的用户状态似乎已经从该会话中的该用户中消失
12) userbean返回(false)它们没有登录//,但它们是
13) 菜单显示登录按钮//他们无论如何都无法登录,因为服务器已经将他们视为已登录,在该会话中(Servlet异常:在用户标识已经存在的情况下尝试重新登录)

为什么使用managedbeans我可以看到userbean在会话范围内维护其数据,而使用cdi-beans却不能?我被难住了。如果必须的话,我会换回托管bean,这不是什么大问题,但我想知道我搞砸了什么。




我在UserBean的init方法中添加了一些调试代码,看起来系统将SessionScoped UserBean视为RequestScoped。也就是说,它在每次调用时都进行初始化。

@PostConstruct
public void init() {
    if (userInfo == null) {
        userInfo = new UserInfoDTO();
        userInfo.setUserName("Guest");
        List<String> guestGroup = Arrays.asList(CoreUserGroupType.GUEST.toString());
        userInfo.setUserGroups(guestGroup);
        System.out.println("UserBean.init INSIDE Init If Statement");
    }
    System.out.println("UserBean.init OUTSIDE Init If Statement");
}

如果它真的表现得像SessionScoped,那么userInfo对象不会每次都为null,也不会每次都执行"If"语句。但它在对UserBean的每次调用中都在执行。所以这才是问题的症结所在。事实上,如果它表现得像在会话范围内一样,它就不会在每次调用时都命中init方法,因为它仍然会被初始化。

我是否没有正确创建一个sessionscoped bean?看起来是这样,但我不知道怎么回事。如前所述,当定义为managedbean时,此代码运行良好。

更改为正确的sessionscoped导入,一切正常。除了我的骄傲,什么都没有伤害。

相关内容

  • 没有找到相关文章

最新更新