Struts2 Guice 3.0@ScopeSession用户对象在会话超时时不失效

Struts2 Guice 3.0@ScopeSession用户对象在会话超时时不失效,struts2,guice,session-timeout,inject,Struts2,Guice,Session Timeout,Inject,我有一门课: @SessionScoped public class LoggedUser { private User user; ... } 如果用户登录到我的应用程序,我将使用它来跟踪 在我的Struts2应用程序中,我有一个拦截器来检查用户是否已登录,如果没有,他是否已转发到登录页面 public class LoggedUserInterceptor extends AbstractInterceptor { private static final l

我有一门课:

@SessionScoped
public class LoggedUser {
    private User user;
    ...
}  
如果用户登录到我的应用程序,我将使用它来跟踪

在我的Struts2应用程序中,我有一个拦截器来检查用户是否已登录,如果没有,他是否已转发到登录页面

public class LoggedUserInterceptor extends AbstractInterceptor {

    private static final long serialVersionUID = 2822434409188961460L;

    @Inject
    private LoggedUser loggedUser;

    @Override
    public String intercept(ActionInvocation invocation) throws Exception { 
        if(loggedUser==null || !loggedUser.isLogged()){
            return "login";
        }
        return invocation.invoke();
    }

}
会话超时时会出现问题。对象LoggdeUser从不为null或删除。我总是最后一个例子

我添加了一个会话侦听器

public class SessionListener implements HttpSessionListener {

    private static Logger logger = Logger.getLogger(SessionListener.class.getName());

    @Override
    public void sessionCreated(HttpSessionEvent event) {
        logger.info("sessionCreated = " + event.getSession().getId());
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent event) {
        logger.info("sessionDestroyed = " + event.getSession().getId());
    }

}
我看到sessionDestroyed被调用,但是当我再次进入我的拦截器时。。不会为新会话重新创建LoggedUser

为什么?

我的Struts2登录操作如下

public class LoginUserAction extends ActionSupport implements ModelDriven<LoggedUser>, ServletRequestAware {
    ...
    @Inject
    private LoggedUser loggedUser;

    public String execute() throws Exception {
        ...
        loggerUser.setLoggedTime(now);
        ...
        return SUCCESS;
    }
公共类LoginUserAction扩展ActionSupport实现模型驱动的ServletRequestAware{
...
@注入
私人LoggedUser LoggedUser;
公共字符串execute()引发异常{
...
setLoggedTime(现在);
...
回归成功;
}
我在web.xml中也添加了这一点

session-config session-timeout 2 /session-timeout /session-config 会话配置 会话超时2/会话超时
/会话配置我不知道guice,但该会话可供拦截器使用,并可通过SessionAware随时供操作使用:

ActionInvocation提供对会话的访问。以下是“身份验证”侦听器的一部分。如果没有“用户”对象,则返回Action.LOGIN

public String intercept(ActionInvocation invocation) throws Exception {
    Map session = invocation.getInvocationContext().getSession();
    appLayer.User user = (appLayer.User) session.get("User");
    if (user == null){
        return Action.LOGIN;
    }
    return invocation.invoke();
}
我仅在用户登录时将用户对象放置在会话上

在登录操作中,我将用户对象放置在会话上:

public class Login extends ActionSupport implements SessionAware {
  private Map<String, Object> session;
  private String userName;
  private String password;

  public String execute() {
    //use DB authentication once this works
    //if ("ken".equalsIgnoreCase(userName) && "ken".equalsIgnoreCase(password)){
    try {
        User user = new User(userName, password);
        session.put("User", user);
        return ActionSupport.SUCCESS;
    } catch (Exception e) {
        System.out.println("There was an exception" + e.getMessage());
        return ActionSupport.LOGIN;
    }
  } 

  public void validate() {
    String user = this.getUserName();
    String pass = this.getPassword();
    //This block is a bit redundant but I couldn't figure out how
    //to get just the hibernate part to report an exception on Username/pass
    if (!StringUtils.isBlank(this.getUserName()) && !StringUtils.isBlank(this.getPassword())) {
        try {
            Class.forName("com.ibm.as400.access.AS400JDBCDriver").newInstance();
            String url = "jdbc:as400://192.168.1.14";
            DriverManager.getConnection(url, user, pass).close();
        } catch (Exception e) {
            addFieldError("login.error.authenticate", "Bad Username / Password");
        }
      }
      if (StringUtils.isBlank(getUserName())) {
        addFieldError("login.error.name", "Missing User Name");
      }
      if (StringUtils.isBlank(getPassword())) {
        addFieldError("login.error.password", "Missing Password");
      }
    //else both are blank don't report an error at this time
  }

  ... getters/setters....
  }//end class
公共类登录扩展ActionSupport实现SessionAware{
私人Map会议;
私有字符串用户名;
私有字符串密码;
公共字符串execute(){
//一旦成功,请使用DB身份验证
//如果(“ken.equalsIgnoreCase(用户名)&&“ken.equalsIgnoreCase(密码)){
试一试{
用户=新用户(用户名、密码);
session.put(“用户”,User);
返回ActionSupport.SUCCESS;
}捕获(例外e){
System.out.println(“出现异常”+e.getMessage());
返回ActionSupport.LOGIN;
}
} 
public void validate(){
字符串user=this.getUserName();
String pass=this.getPassword();
//这个区块有点多余,但我不知道怎么做
//只让hibernate部分报告用户名/密码异常
如果(!StringUtils.isBlank(this.getUserName())和&!StringUtils.isBlank(this.getPassword()){
试一试{
Class.forName(“com.ibm.as400.access.as400jdbdriver”).newInstance();
String url=“jdbc:as400://192.168.1.14”;
getConnection(url、用户、密码).close();
}捕获(例外e){
addFieldError(“login.error.authenticate”,“错误的用户名/密码”);
}
}
if(StringUtils.isBlank(getUserName())){
addFieldError(“login.error.name”,“缺少用户名”);
}
if(StringUtils.isBlank(getPassword())){
addFieldError(“login.error.password”,“缺少密码”);
}
//否则两者都为空,此时不报告错误
}
…接受者/接受者。。。。
}//末级

如果我没记错的话,这至少部分来自“Struts2在行动”.无论如何,我非常相信DI,但由于会话可以从拦截器访问,而且操作我也不介意。

我对Struts2一无所知,但我猜拦截器的作用域比会话的作用域更广。换句话说,拦截器实例比会话保持的时间更长。Guice不能也不会会话结束时,不要将注入的字段设置为
null
,也不会自动重新注入对象

如果在生命周期较长的对象中使用生命周期较短的对象(例如
SessionScoped
对象中的
RequestScoped
对象或单例中的
SessionScoped
对象),则需要为生命周期较短的对象注入
提供程序

就你而言,我认为这可能是你需要的:

public class LoggedUserInterceptor extends AbstractInterceptor {
    private static final long serialVersionUID = 2822434409188961460L;

    @Inject
    private Provider<LoggedUser> loggedUserProvider;

    @Override
    public String intercept(ActionInvocation invocation) throws Exception {
        LoggedUser loggedUser = loggedUserProvider.get();
        if(loggedUser==null || !loggedUser.isLogged()){
            return "login";
        }
        return invocation.invoke();
    }
}
公共类LoggedUserInterceptor扩展了AbstractInterceptor{
私有静态最终长serialVersionUID=282434409188961460L;
@注入
私人提供商loggedUserProvider;
@凌驾
公共字符串截获(ActionInvocation调用)引发异常{
LoggedUser LoggedUser=loggedUserProvider.get();
if(loggedUser==null | |!loggedUser.isLogged()){
返回“登录”;
}
返回invocation.invoke();
}
}

最简单的方法是最终在登录时将令牌放入会话中,并使用拦截器进行检查

@Override public String intercept(ActionInvocation invocation) throws Exception { loggedUser = (LoggedUser) invocation.getInvocationContext().getSession().get(LoggedUser.SESSIONTOKEN); if(loggedUser==null || !loggedUser.isLogged()){ logger.info("loggedUser not present in session"); return "login"; } return invocation.invoke(); } request.getSession().setAttribute(LoggedUser.SESSIONTOKEN, loggedUser); @凌驾 公共字符串截获(ActionInvocation调用)引发异常{ loggedUser=(loggedUser)invocation.getInvocationContext().getSession().get(loggedUser.SESSIONTOKEN); if(loggedUser==null | |!loggedUser.isLogged()){ logger.info(“loggedUser不在会话中”); 返回“登录”; } 返回invocation.invoke(); }

在行动中

@Override public String intercept(ActionInvocation invocation) throws Exception { loggedUser = (LoggedUser) invocation.getInvocationContext().getSession().get(LoggedUser.SESSIONTOKEN); if(loggedUser==null || !loggedUser.isLogged()){ logger.info("loggedUser not present in session"); return "login"; } return invocation.invoke(); } request.getSession().setAttribute(LoggedUser.SESSIONTOKEN, loggedUser); request.getSession().setAttribute(LoggedUser.SESSIONTOKEN,LoggedUser);

如果我不能让它与DI一起工作,我会像以前一样手动进行会话。但是这次我真的想知道我错过了什么使它工作。我也这么做了…你能为注释@Inject添加导入吗?S2也有一个@Inject。我尝试了你的解决方案。问题是,该对象从未从因此,当会话被破坏时,用户总是连接到事件。