【问题标题】:Sessions in struts2 applicationstruts2 应用程序中的会话
【发布时间】:2011-04-01 05:46:08
【问题描述】:

我创建了一个网络应用程序,我需要在其中维护会话 如果存在用户会话,那么它才会允许用户查看 jsp。

我以前使用过 jsp servlet,但我是 struts2 的新手。

我在这里在我的操作类中设置用户名

修改后的代码

private HttpSession session;

public void setSession(HttpSession session) {
    // TODO Auto-generated method stub0
    this.session = session;
}

public HttpSession getSession() {
    return session;
}

public String getLoginStatus(){     
    session = request.getSession();
    session.setAttribute("userName", loginBean.getUsername());
    return SUCCESS;
}

现在,当我在某个操作后被重定向到下一页时,它会显示一次会话值。之后,在每一页上,我都在会话中找到空值。

<%
    String userName = (String)session.getAttribute("userName");             
    System.out.println(userName);                        

    if(userName == null || userName.equals("") ){
        response.sendRedirect("login.jsp");
    }

%>

我在某处读到,动作类会话的范围仅限于一页 - 我该如何解决这个问题?

任何例子都会对我很有帮助。

【问题讨论】:

    标签: java session jakarta-ee struts2


    【解决方案1】:

    您当前的代码存在一些问题。

    • 您应该使用拦截器来强制用户登录,而不是尝试在 JSP 中强制它。 JSP 应该只用于展示,而不是用于流控制。
    • 您应该避免在 JSP 中使用 scriptlet(代码块)。这在很久以前就被弃用了,并且被广泛认为是 MVC 应用程序中非常糟糕的做法。
    • 您可以直接访问 JSP 中的会话值。除非您需要访问操作本身内部的会话,否则您无需在操作中实现 SessionAware 接口。
    • 您应该将用户重定向到登录操作,而不是直接到 JSP 页面,否则您将绕过 Struts2 框架并失去使用该框架的好处。

    登录示例

    下面是一些使用 Struts2 框架创建基本登录系统的示例代码。

    需要登录

    这部分是可选的,但一般来说,并不是Web应用程序中的所有页面都需要用户登录。因此,让我们创建一个名为LoginRequired的接口。如果用户尚未登录,任何实现此标记接口的操作都将重定向到登录页面。

    注意:如果您愿意,可以使用注解代替,但在本例中,我将使用接口。

    public interface LoginRequired {}
    

    拦截器

    拦截器将强制用户登录任何实现LoginRequired接口的请求操作。

    public class LoginInterceptor extends AbstractInterceptor {
        @Override
        public String intercept(final ActionInvocation invocation) throws Exception {
            Map<String, Object> session = ActionContext.getContext().getSession();
    
            // sb: feel free to change this to some other type of an object which
            // represents that the user is logged in. for this example, I am using
            // an integer which would probably represent a primary key that I would
            // look the user up by with Hibernate or some other mechanism.
            Integer userId = (Integer) session.get("userId");
    
            // sb: if the user is already signed-in, then let the request through.
            if (userId != null) {
                return invocation.invoke();
            }
    
            Object action = invocation.getAction();
    
            // sb: if the action doesn't require sign-in, then let it through.
            if (!(action instanceof LoginRequired)) {
                return invocation.invoke();
            }
    
            // sb: if this request does require login and the current action is
            // not the login action, then redirect the user
            if (!(action instanceof LoginAction)) {
                return "loginRedirect";
            }
    
            // sb: they either requested the login page or are submitting their
            // login now, let it through
            return invocation.invoke();
        }
    }
    

    您还需要一个用于显示和处理登录页面的LoginAction 和一个用于使会话无效或清除会话的LogoutAction

    配置

    您需要将拦截器添加到您的堆栈中,并为“loginRedirect”创建一个全局结果映射。

    <interceptors>
        <interceptor name="login" class="your.package.LoginInterceptor"/>
    
        <!-- sb: you need to configure all of your interceptors here. i'm only
             listing the one we created for this example. -->
        <interceptor-stack name="yourStack">
            ...
            <interceptor-ref name="login"/>
            ...
        </interceptor-stack>
    </interceptors>
    
    <global-results>
        <!-- sb: make this the path to your login action.
             this could also be a redirectAction type. -->
        <result name="loginRedirect" type="redirect">/login</url>
    </global-results>
    

    【讨论】:

    • 默认拦截器之一不提供此功能吗?
    • 不,不是。用户身份验证和授权通常是一个非常自定义的解决方案。
    • 这个解决方案很好用!如果您有很多需要身份验证的操作,例如:web 应用程序,我建议您反之亦然,并创建一个名为 PublicAccess 的接口,如果操作是 PublicAccess 的实例,则现在在您的拦截器中可以调用
    【解决方案2】:

    要维护会话,请在您的操作类中使用 SessionAware 接口并实现 int public void setSession(Map m) 将属性作为map中的键值对 只需购买检索密钥即可从任何地方访问。

    例如动作类

    import org.apache.struts2.interceptor.SessionAware;
    
    import com.opensymphony.xwork2.ActionSupport;
    
    public class LogingEx extends ActionSupport implements SessionAware{
        private static final long serialVersionUID = 1L;
    
        private String stuname,stuage,country;
        private int stumarks;
        Map m;
    
        public String getStuname() {
            return stuname;
        }
        public void setStuname(String stuname) {
            this.stuname = stuname;
        }
    
        public String getStuage() {
            return stuage;
        }
        public void setStuage(String stuage) {
            this.stuage = stuage;
        }
    
        public String getCountry() {
            return country;
        }
        public void setCountry(String country) {
            this.country = country;
        }
    
        public int getStumarks() {
            return stumarks;
        }
        public void setStumarks(int stumarks) {
            this.stumarks = stumarks;
        }
    
        public void setSession(Map m)
        {
            this.m=m;
        }
    
        public String execute()
        {
            m.put("a",stuname);
            m.put("b", stuage);
            m.put("c",stumarks);
            m.put("d",country);
    
            return SUCCESS;
        }
    
    }
    

    来源:http://www.java4s.com/struts-tutorials/example-on-struts-2-sessionaware-interface/

    【讨论】:

      【解决方案3】:

      我没有理由使用这种Map 来授权用户。如果您的要求只是针对会话验证用户,那么我建议使用 Filter 而不是某些类中的某些映射,这种映射的问题是一旦会话无效就删除会话对象,当然您可以使用 @ 987654324@ 使其工作,但我想最好通过Filter 验证而不是Map

      除此之外,您还可以查看许多安全框架(例如 Apache Shiro),以使您的任务更简单、更健壮。

      【讨论】:

      • 映射是 Struts2 框架的一部分,是 HttpSession 的外观。因此,您的担忧是无效的。
      • @Steven Benitez - 但过滤器仍然是授权的最佳方式......不是吗?
      • 不一定。拦截器也是一个不错的选择。无论哪种方式,您都需要在会话中存储一些内容以表明用户已通过身份验证。
      【解决方案4】:

      您的 Action 类是否已经实现了SessionAware 接口?

      编辑:

      试试这个(这是一个struts2风格的解决方案):

      public class anAction implements SessionAware{
          private Map<String, Object> session;
          public Map<String, Object> getSession() {
               return session;
          }
          public void setSession(Map<String, Object> session) {
               this.session = session;
          }
          public String getLoginStatus(){
               session.put("userName", "test");  //Hard code here for testing.
               return SUCCESS;
          }
      }
      

      然后使用您的 jsp 代码获取页面上的用户名。我已经在我的机器上测试了这种方法并且它有效。

      编辑2: 顺便说一句,这种登录检查可以通过 Struts2 框架提供的“拦截器”轻松而优雅地完成。

      【讨论】:

      • 之前我已经实现了 SessionAware 但我已经删除了它仍然面临同样的问题
      【解决方案5】:

      不需要实现 SessionAware。

      public class LoginAction extends Actionsupport
      {
        private Map<String, Object> session;
        //Getter and Setter method
         public String execute() throws Exception {
            session=ActionContext.getContext().getSession();
            session.put("userName", "test");
           return super.execute();
         }
      } 
      

      【讨论】:

      • 如果您计划对您的操作进行单元测试,SessionAware 方法会更好,因为它允许您轻松注入假地图,而无需模拟线程本地 ActionContext。
      【解决方案6】:

      以下 journaldev 文章在http://www.journaldev.com/2210/struts-2-interceptor-tutorial-with-custom-authentication-interceptor-example上方的 Steven 回复的同一行中有更多详细信息

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多